Efficiently writing Unit Tests

Writing Unit tests take a lot of time. It can discourage you from spending time on them. But, there are ways we can mitigate this churn. Let's split the problem by looking at where's the overhead. I found the following items among others to be very time-consuming -

1. DI (Dependencies Injection) - It takes time to mock and inject the services

2. Data Setup - Manually setting up the test data is not a quick task. For example - if you are trying to test code for inserting a new customer, setting up the required fields will take time

3. Asserts - These can get confusing, and sometimes they are not intuitive

4. Code Coverage - It's not only important to know - how much of your code is covered by tests but also whether you are prioritizing testing frequently used code over seldom one

5. Chain Calls - Quite a few keystrokes can be saved if we can chain calls. It's also called the Fluent Interface. After all, characters typed are exponentially proportional to the time required for completion

6. The overall Grind - What if we don't have to write Unit tests at all but still able to Unit test our code. Let that sink in for now


Now that we've laid down the entire map, let's dig in.

1. DI including mocks

For a minute, imagine yourself writing tests for the following code. It's a nightmare, and for the same reason - I call it Constructor Injection hell. When I first found myself in this situation - I said there gotta be a better way to test it. I'm glad there are at least a couple. Another option is - you can build a graph of mocks, and call the mocks that you need from there; like a dictionary.

 2. Data Setup

 It's an important part of Unit testing, and it does consume a lot of time to - figure out, write, and put together test data. Luckily, there are a few ways to automate it. 

 i. Bogus - fake data generator

ii. If you have to build a data factory by yourself then here's a way

3. Asserts

Asserts can get confusing. I find Shouldly a better alternate. Not only it's super descriptive but also way more clear.

4. Code Coverage

You'd want to know where does your unit testing coverage of your code stands - Right? As I mentioned earlier, some parts of your code might be used frequently than others. I'm listing down some tools that can help you here -

i. Coverlet: It's a code coverage framework for .Net, and .Net Core. Make sure to use a ReportGenerator tool to get a better visual of where does your code coverage stand.

ii. Resharper, FxCop, Roslynator - These are some additional tools that can be used to locate dead code, and avoid writing tests for them. Maybe you should also think about why that code is there in the first place.

5. Chain Calls

Have you seen My Tested App? It has some neat features but the code requires some changes before it can be used in a .net core solution.

6. The overall Grind

It's better suited for another blog post but here's brief - Rust has testing baked into the framework. It provides inline testing ability; which means no separate Unit Test projects as we have in .net. You'd have to run Rust compiler in test mode, and it will find the methods with Test attribute. I believe this approach could turn out to be a huge time saver for C# community. Hoping to make some leads into it during the coming weeks or maybe months :-). Until then,

Happy Testing.




Add comment