How to start Unit-Testing
Some of you think “Why does this dude write about Unit-Testing in 2016? Its all set as daily standard for devs!”. I agree: old topic. But even in the last few months I met many developers who did not write any unit-tests at all or devs who have written them only once in a while. Especially in project business where the schedule is close unit-testing are dropped as one of the first things. But I met also devs in product business who didn’t do any testing even if they run into regression bugs regularly. And hell yes, I don’t write unit-tests for all of my code either! People who know me know how hard this is for me to admit.
So here I put some thoughts and tips how to start more easily with unit-testing. Hopefully I can tear down some walls.
I don’t extend to much on the why as many others have written about it already. Just my personal motivation to write unit-tests:
- Besides all the more official pros the one matters for me is that I can sleep better – especially before and after releases – when I know my test-suites are green. I know “hey, the basics are working and I did not break things I once tested. So if something arise it’s probably a border-case issue or at least something within the new stuff so its not high-priority.”.
- Second I like to do a good job in design and programming software. Unit-Tests allows me to kind of ensure this the way I can write the tests for the functionality I expect and validate it now and for all times.
- Finally I am a developer! I like to spent my time way more on writing code then do stupid repetitively manual testing. Automating things is deep in a Dev’s DNA and that’s a good thing. Write a script/code once – use it many times. That’s how Developers to it! We have to power to do magic things that other can’t do. Its awesome to be Dev – use your power!
Don’t have time to test all?
Easy! I don’t have it either – at least not always. You can start with the most important parts. You will never ever have 100% code coverage. Even 80-90% is hard. And who cares about those values anyway! Don’t get me wrong – I like to run code-coverage from time to time to see what parts of the code are lacking unit-test. But the fixed percentage number can lead to write strange unit-tests just to get another percent code-coverage.
Start small
Give yourself success and start small. When writing your next peace of code think about it: “What is the core logic of this? Let’s write a small unit-tests which ensures this basic functionality.”. Start using baby-steps will give you success experience which is very important to not end frustrated and throw it away again.
You probably will find code you need to refactor to test it. Even after years of unit-testing I find myself refactoring code because of writing the unit-tests showed it is not nicely organized (eg. separated). So writing unit-tests leads to writing better productive code. That’s a real good side-effect of unit-testing / test-automation.
What should I test first?
So where to start with unit-testing? Where should I spend my time first regarding writing automated unit-test? Here is my priority list:
- Test core functionality first. For me this normally is the domain-logic / business-logic. This is the hart of the app. Its the part that brings in the real value. If nothing else is validated but this part of your app should be.
- Regression bugs: If a bug will be re-introduced in a later release again even if it was fixed already, its called a “regression bug”. These should never happen. It makes customers really unhappy. So if I fix a bug I try to write a unit-test for it do be sure this bug will never ever make its way into a future release.
- Extend automated tests as needed and as you can make time available for it.
Important: do start write unit-tests where it make the most sense and adds the most value! They don’t have to be perfect. They don’t need to shine.
How can I reduce the time it needs to write unit-test?
First, it needs practice. You will learn what make testing easier and what doesn’t. Let me introduce you my time-savers:
- Write clean-code using SOLID principals – especially useful for writing unit-tests is the “Single Responsibility” principal. This basically means that one class should have only one job. Keep classes small und tire them to a single purpose. This results in clean, maintainable and extensible code and also make unit-testing for those classes a lot easier. Together with “Dependency inversion” principle (DI) this is a real enabler as you don’t need to mock/fake the whole universe.
- Don’t forget about your developer skills when writing unit-tests! Use language features like OOP, inheritance, extension methods and handy patterns. You can make base-classes and reusable helper. Cool coding stuff! Don’t do stupid copy-paste just because these are unit-tests. Use you engineering power and write clean code in unit-tests. They get more maintainable and it makes a lot more fun to write unit-tests.
- Don’t do automated UI testing until you really, really, really need it. This needs a lot of time and they normally tend to need a lot of maintenance time. Instead use patterns like MVVM and *only* test your view-model logic.
Example:
Let’s image you are writing some migration software which reads from one datasource, transform the data and write it to another datasource.
Instead of writing one class that read, transform and write you should have written tree classes regarding single responsibility: one for reading, one for transforming and one for writing.
You application can chain these classes together using interfaces for them as promoted by dependency inversion.
Now you have tree classes and three interfaces. What do you think will be the most important part to write unit-tests for? Right: the transformation. This is why your app exists at all so make sure this central component works. Its easy as you have interfaces for reading and writing. You can mock or fake them easily and have tests ready.
public interface IMyReader { IEnumerable Read(); } public interface IMyWriter { Write(string data); } public interface IMyTransformer { void Transform(); } public class MyTransformer : IMyTransformer { public MyTransformer(IMyReader reader, IMyWriter writer) { ... } public void Transform() { foreach (var line in reader.Read()) { // DO TRANSFORM writer.Write(line); } } }
Now the unit-tests for MyTransformer
can be as easy as follows:
var reader = A.Fake(); reader.CallTo(() => Read()).Returns("test input string"); var writer = A.Fake(); reader.CallTo(() => Write()).MustHaveHappened(); var transformer = new Transformer(reader, writer); transformer.Transform(); // TODO: Additional test of the transformation result
Note: The above code use my famous mock/fake-library “Fake it easy” (best-of Moq and Rhino Mocks).
Libraries
To get you started writing unit-tests for your C# code here the libraries / tools I use for most of my testing:
- NUnit – Unit-Testing framework
- NUnit Test Adapter – Allows running NUnit tests on VSTS/TFS and within Visual Studio Test-Runner
- MSTest – Unit-Testing framework from Microsoft
- Fake it easy – Mock and Fake library to setup fake implementations in no time
- FluentAssertion – Let’s one write the assertions with a nice and fluent syntax
- R# Testrunner – To run tests during development
Now go and write unit-tests!
Categories