I. Introduction
Soon after software development has emerged, it became obvious that any application beyond a homework needs testing. Testing evolved naturally along with frameworks, both on client side and server side and now we are talking about Test-driven development and Behavior-driven development(e.g. Cucumber). Of course, most efficient tests are automatic ones.
A couple of years ago, we had the opportunity to start a project from scratch (MDW Automatic Testing along with Claudiu) and I said to my self: why not develop a small framework to easily add automatic tests?
Since back then ASP.NET Core was not mature enough to go into production, we stuck to the more solid ASP.NET MVC 5, along with its natural companion, Entity Framework 6. On the client side, we used AngularJS(Angular was not mature enough back then).
So, this article will focus on automatic testing using this tech stack, but most of the concepts also apply to other tech stacks.
II. Unit testing
Simply put, unit testing refers to testing the functions in your code.
Unit tests represent the base of the automated test pyramid and from my personal experience, they are often skipped, because they require a lot of coding and thus more time (also check this nice article about levels of testing). We made a compromise and have chosen to cover critical functionality with unit tests and use integrative tests for the rest.
In order for the code to be unit-testable some tools and design-patterns were used to cover the following concepts:
- Dependency Injection — we chose Ninject. Of course, there are alternatives, but this seemed to be most versatile. This allows to easily replace a service dependency when needed (e.g. with a mock object)
- A mocking framework — we chose NSubstitute . This allows to easily to replace classes or functions for unit testing.
- A unit testing framework — we use NUnit. It integrates nicely in Visual Studio and we use it to run all our tests (including Selenium Web driver ones).
- Generic repositories — a design pattern that involves creating a generic class that handles basic data operations (add, insert, insert bulk, update, update bulk etc.). Unfortunately, Entity Framework 6 is not very friendly when it comes to dependency injection and mocking, so generic repositories are of good use since that can simply be replaced with some generic in-memory repositories.
NOTE: thankfully, ASP.NET Core 2.0 was built with dependency injection in mind and comes with an in-memory database provider that makes unit tests much easier.
Enough talk, let’s dive into some code.
- The generic repositories
All generic repositories implement a single interface (see below). Besides the regular (non-cached) repository and the in-memory one, there is also a “cached” one that is plugged for some entities to avoid database fetches (typically mapped to rarely changed and relatively small tables).
Read the complete article here.
Written by Alexandru Dragan, METRO SYSTEMS Romania