My unit testing stack in .NET
I'm a big fan of unit tests as specification for objects within your application. As a .NET developer, we are fortunate to have many mature libraries and tools to enhance our unit testing experience. This article lists the tech stack I prefer at this moment in time.
XUnit, Autofixture, Moq and FluentAssertions. Easy peasy!
XUnit
XUnit is a highly extensible, cross-platform FOSS testing framework. With 184 million downloads (at the time of creation of this article), it has become the de facto standard when it comes to unit testing in .NET.
Pros:
It does deviate slightly from the traditional approach of unit tests and in my opinion, fits fairly well with my perspective of unit tests as specifications for classes. It also clears the runway, so to speak, to do the right thing. Performance of unit tests has always been a problem. Parallelism requires isolation of unit tests, which has received greater focus in XUnit. The idea is to keep individual tests isolated by doing their own setup and teardown as far as possible. Of course, shared resources or setups are not banned altogether. One can still use constructors, class fixtures and collection fixtures, if you absolutely need it.
Nomenclature has changed as well. Facts are invariant tests, a truth statement about the functionality you're trying to specify (test). Theories are known to be true under a given set of scenarios. In other words, theories are parameterized tests.
Of course, all of this might seem cosmetic to some. My preference for XUnit is not, however, purely philosophical in nature. Looking at the extensive ecosystem around XUnit that continues to develop and thrive makes it a practical choice as well. SpecFlow extensions, AutoFixture extensions, etc. are but mere examples of this. In my opinion, a coherent stack based on XUnit makes it greater than the sum of its parts.
Cons:
The installation and setup experience isn't great to be honest, primarily because the developer is expected to explicitly install Test SDK and Visual Studio runner (when using VS, of course), which isn't super obvious to some. But apart from that initial bit of friction, I cannot really fault it.
Alternatives:
The traditional NUnit and MSTest do still have a significant following, which could be considered.
Autofixture
Testing frameworks are only the tip of the iceberg. Next few sections talk about the most common utilities within unit tests. Typically, when you write unit tests, you rely heavily on fakes, mocks and stubs, in order to simulate the condition and the outcome you wish to verify. So let's begin with fakes and stubs first.
Autofixture is commonly thought of as a standard test data builder, but it's current self-professed intent is to automate non-relevant test fixture setup. That nuance is what distinguishes it from other fake data generators. Excellent frameworks as they are, Autofixture focuses on generating anonymous variables - values which don't matter.
The Autofixture ecosystem contains many utilities that make it easy to combine it with many other libraries and frameworks like Moq, etc. This is consistent with the ethos of trying to keep test setup as simple as possible.
Pros:
Autofixture has a fantastic cheat sheet, which should be enough to get anyone going with creating fakes and stubs. The API is easy, simple and succinct, whether you're creating full-blown stubs or partial stubs. Additionally, it allows users to customize instantiation of particular objects through Specimen Builders and Customizations. More on that later.
Cons:
The big drawback, and I'm sure supporters of Bogus and GenFu would agree with me on this, is that fake data generated by the latter frameworks is more intuitive. Names are names, places are places, post codes are post codes, etc. Autofixture, on the other hand, generates anonymous variables. In other words, gibberish.
Truth be told, I haven't personally found that to hamper my testing much. What I get out of Autofixture supercedes this. Again, like I said before, having a good coherent stack makes one more productive in my opinion, but your mileage might vary.
Alternatives:
Bogus and GenFu are two frameworks that immediately pop up with a cursory search on the web. Bogus can be extremely powerful, especially when used with Autobogus.
Moq
Mocking in many ways is the mainstay of most unit tests. It is far easier to mock certain parts of dependencies and verify those behaviours when appropriate. Moq is an extremely popular mocking framework that allows you to create mocks with verifiable behaviour or outcomes. I don't think I need to say much here, it is simply excellent.
Pros:
There's not much I can say here that hasn't been said already. The web is overflowing with articles about Moq.
Cons:
Lack of support for sealed classes is not so much a con, rather a limitation for obvious reasons. I usually turn those into stubs or fakes.
Alternatives:
FakeItEasy and Rhino Mocks are two alternatives that immediately come to mind. I'll leave it for the reader to investigate them further.
Fluent Assertions:
Super easy fluent DSL for assertions. I'm a big fan of clearing the runway to do the right thing; the API makes it fairly easy to produce meaningful messages when tests fail. And that is extremely handy.
Alternatives:
Shouldly is a similar fluent DSL. I'm afraid I haven't played with it enough to do a good comparison. Take your pick.
So there you have it. My favourite unit testing stack when doing .NET development. Hope this helps you achieve better results in your unit testing journey. In an upcoming article, I will demonstrate how these can be combined to write simpler, succinct and eminently readable tests.
Until next time, namaskaar!