How to do the Unit testing with xUnit
When we talk about unit testing in .NET applications, xUnit is undoubtedly the preferred library of most programmers. However, in addition to applying good testing practices.
It is necessary to know and take advantage of the available resources of the tool. So that your tests are clean and easily maintainable.
In this blog, we will cover the main features of xUnit, far beyond the traditional Fact.
To start chatting about xUnit features, nothing better than talking about your most used feature, Fact.
As the name itself induces, the idea is to test a fact, something “unique” and objective. This is the most widely used feature in the library and can easily meet all your needs in a unit test project.
With this structure it is possible to do any type of test, however. When the “logic” of the test needs to be the same, modifying only the input parameters, the duplication of the test code is inevitable. Obviously in some cases “duplication” may be acceptable and make sense, but for the most part, it makes no sense at all.
To resolve the previously presented problem, xUnit has a feature called Theory, in which the logic is the same for a set of different inputs and outputs. Rewriting the previous tests would look something like:
This code would run twice, once for each InlineDate of the annotation, passing its respective parameters. In the test results, it is subdivided into the number of tests that are run allowing you to view which option failed. Using Theory allows you to reuse your test code for several different inputs/outputs.
A great option to make it easier to maintain tests on eventual changes.
In some cases, your InlineData may get too large by polluting the tests. Or, you may need to pass objects as a parameter. But as we know, you can’t instantiate them and pass them via method annotation.
To resolve this issue, let’s exemplify the use of member data.
In this slightly larger example, we were able to use objects as parameters and for this we need to create an IEnumerable<object> to provide the necessary inputs. Simply put, it is a list of objects (which will be inputted into the test method) within another list (test cases).
As more complex, it may seem. The idea is to prefer objects to many parameters in the signature of a method in our architecture. Given this, using this structure may be the best option.
If your test is getting too long, you can choose to put one more attribute, ClassData, which is very similar to MemberData, but you get a class that inherits from IEnumerable<object>, so it’s easier to isolate the “test case templates” from the implementations themselves.
Finally, we can also use the “hybrid” form. A merge between MemberDataand ClassData (but it is purely MemberData separating the parameters into an external hehe class).
In this post we saw that in addition to Fact it is possible to reuse a lot of the code and logic of the tests with the use of Theory and its possible forms of data input.
Do not forget that tests should also be elegant and follow the principles of clean code, after all.
If you have your entire system tested and make any modification. At least one test should break and you should adjust it to its modification. To ensure that the behavior of the system test all possibilities and fail when minimal changes are made.