Introduction
As obvious as it may sound, writing unit tests is all about writing code. The code you find in unit tests, in particular, requires an ad hoc API - the test API, fakes, mocks, and assertions - but it is plain code that invokes other code in order to achieve some results. The results are not concrete data to consume in some way, but rather a Boolean response to the question "Will this function or method work as expected?"
This basic fact has a fundamental spin-off. Sometimes writing the unit test is easy and requires a trivial amount of logic; sometimes, instead, it requires a bit of attention, design considerations, maybe some tricks and workarounds much like those you may resort to when writing "regular" code aimed at producing some concrete result for some users. Writing code to test other code would not be a particularly hard task if only the code to test were written with testability in mind. Because we don't live in a perfect world, this is not always the case. And just this fact determines the need of smart tricks and workarounds to test certain parts of the code.
In the article, I'll focus on two particular situations: dealing with dependencies and testing private members. I'll be discussing this in the context of ASP.NET MVC and MSTest, but without any significant loss of generality.
First Arrange, then Act, finally Assert
The schema of a unit test is neat and clear. First, you get hold of an instance of the class you intend to test that is properly configured. Second, you perform on that instance the action whose results you intend to test. Finally, you go through one, or perhaps more, assertions to check actual results against expected results. Using the Visual Studio MSTest environment and taking a simple ASP.NET MVC controller class as an example, here's what you may get:
Everything is easy to write and even easier to assert. From here, you can conclude that writing unit tests is not a big deal.
Sometimes, however, writing assertions is not so obvious. What if the method doesn't produce any significant outcome? Imagine a void method or a method that always returns a successful response except when it throws. In both cases, the actual response you get tells you very little about the actual outcome of the execution. Arguing that this occurs because the code was not designed for testability is probably correct, but doesn't really help you out of the situation.
Writing a class with testability in mind entails the ability to identify and properly encapsulate all of the dependencies that class may have on external components. Dealing with dependencies may sometimes take you to a crossroads. You can add test-only members to the class - which is easy but arguable from a design viewpoint - or you can let external code access the internals of a class - which is harder and still arguable, but preserves the purity of the production code.
Dependencies and Injection
Classes with dependencies are just normal business in any significantly complex application. In a testing perspective, you might want to be able to isolate those dependencies when testing dependent classes. For this to happen, dependencies must be injected in the class in some way. If you opt for using an IoC container then you are forced to have classes with an IoC-friendly structure. This means, for example, having classes with a constructor that lists all possible dependencies, like below:
When you choose to use a given IoC container all the way through, then a similar constructor is OK. When it comes to testing, all you do is adding an edited configuration file to the test project where dependencies are resolved in terms of fake dependencies.
If you need mocks, instead, then the constructor that lists all dependencies is there to help. You first arrange dependencies as needed using the mock library of choice and then pass instances down the constructor. Here's a quick example.
The Poor Man's Dependency Injection
In many cases, you just don't want to add the extra complexity of an IoC framework. As many things, IoC containers are powerful tools, but they come at a cost. The poor man's dependency injection (PMDI) is an effective approach that delivers the basic benefits of raw dependency injection at no extra costs. Here's the pattern implemented in an ASP.NET MVC controller class:
In this example, the class has two dependencies. In the default parameterless constructor the dependencies are resolved in a standard way and determine a tight coupling between the CustomerController class and CustomerService and AspNetCacheService classes. This is not an issue when we run the code in production, but what about testability? The second constructor is there only to be used when unit-testing the class.
This is another potential "should-I" issue. Should I keep the second constructor in my production code only because at some point (and before releasing to production) I will do some tests? In some way, adding a test-only constructor seems to spoil the structure of the class. The main drawback I see is that there's no real guarantee that none of your colleagues will ever be calling the test-only constructor from some other place in the application thus potentially breaking the application. (This consideration probably won't apply to the specific demo of ASP.NET MVC, but it is definitely valid in a more general context.) In addition, when you have a test-only constructor you should also guarantee that the logic of the object buildup is the same you use in production. Here's a better refactoring of the code above:
Avoiding Test-Only Members
To keep the design of the class as clean as possible you might want to move elsewhere the members that exist only for testing purposes. An option consists in marking the test-only members as internal to avoid they can be inadvertently invoked by other code. If you mark test-only members as internal, you then need to enable the test code to access them thus bypassing the barrier represented by the internal keyword. This is possible by using the InternalsVisibleTo attribute in the AssemblyInfo.cs file of the core project.
All classes in the MyAppTests assembly - the output of the test project - are now enabled to access any internal member of the assembly where the attribute is used. In this way, the actual code and tests can belong to different projects and assemblies.
What about partial classes? Is it an option to move all test-only members in a partial class as summarized below?
The mechanism of partial classes works as long as the two partial classes belong to the same assembly. In MSTest, this prevents you from using distinct projects within Visual Studio. As a result, it is not probably an option. It may be an option, instead, if you use other test environments outside the classic Visual Studio IDE.
Private Members
Another solution I've been using is based on the facilities that MSTest offers to access private members programmatically. The net effect is that you use neither partial classes nor special assembly attributes but keep the core code of the classes clean and not contaminated with test-only members. Let's assume you have a class with the following constructor in your production code:
In the test project, you add the following extension method to the CustomerController class:
Initialize is a method that extends the CustomerController class and plays the role of the test-only constructor we removed from the production code. The unit test looks like this:
The PrivateObject class is defined in the Microsoft.VisualStudio.TestTools.UnitTesting namespace and is a simple wrapper for some .NET reflection code through which you access methods, properties and fields in a given object that are not private.
The PrivateObject class is also a facility you can use to extend your tests to cover non-public members of a class. Whether you have to test non-public members or not is debated point with many answers and many objections. It is ultimately a matter of how envision things yourself. My take is that you should not overload your team with such tests, but there's nothing wrong in testing some private members.
Summary
Like software in general, testing is not an exact science. And, at the very end of the day, if it works then it's well written, no matter what. There are some magic tools out there (i.e., TypeMock Isolator) through which you can nearly test any sort of class no matter if it was written with only the faintest idea of testability or even less. Most of the time, writing unit tests requires some attributes on the tested code, and some ad hoc members. From the perspective of production code, test-only members are just extra burden and spoil the design of the code. I prefer not to have them on board. On the other hand, this choice has to be balanced in some way by testing private members or finding some sort of middle ground like partial classes or friend members that depend on the capabilities of the test environment of choice.
About Dino Esposito
 |
Dino Esposito is one of the world's authorities on Web technology and software architecture. Dino published an array of books, most of which are considered state-of-the-art in their respective areas. His most recent books are “Microsoft ® .NET: Architecting Applications for the Enterprise” and “...
This author has published 53 articles on DotNetSlackers. View other articles or the complete profile here.
|
You might also be interested in the following related blog posts
Testing.StackExchange – The “StackOverflow” for Software Testers
read more
Beta Testers Wanted: DotNetNuke 5.2.0 Beta Now Available
read more
The myth that TDD or test-first slows you down is true
read more
The Duct Tape Programmer ?!
read more
Using VSTS to Quickly Test Scenarios with Add-In Applications
read more
8 techniques to find problems in your unit tests within 30 seconds
read more
TDD Master Class Day # 3 What I learned today
read more
IDCC conference in Israel – Spet. 14th
read more
Load Testing vs. Profiling
read more
Unit Testing in EF v1 - the database conundrum
read more
|
|
Please login to rate or to leave a comment.