xUnit Best Practices¶
The basics¶
Fact
are tests which are always true. They test invariant conditions. runnerTheory
Theories are tests which are only true for a particular set of data.
Unit test structure using Fact
attribute:
C# | |
---|---|
In addition to the Fact
attribute, you can also use the Theory
attribute on
test methods. Theory runs a test method multiple times, passing different data
values each time. You have a variety of tools for setting the data values to be
passed to your test method.
Unit test structure using Theory
attribute:
C# | |
---|---|
Using InlineData
is easy and straightforward, by there are some limitations,
because being an attribute we can't create object instances. We may use other
sources in such scenarios. Source data for Theory
unit tests can be provided
in may ways:
- Using
InlineData
: it's clear and useful, but limited. - Using
MemberData
: points to an staticproperty
,field
ormethod
to feedTheory
's data source. - Using
ClassData
: uses a class to feedTheory
's data source. It can be an static class or extendTheoryData
provided by xUnit.
Bear in mind that each Theory
with its data set is considered to be a separate
test. In the test results outcome, the runner tells you exactly which set of
data failed, because it includes the parameter values in the name of the test.
Note
Prefer InlineData
when possible over the other alternatives because it's
more comprehensible for the developer, and it offers a bonus point:
allow us to differentiate each execution instance provided by individuals
InlineData
entry in the Test explorer
window.
Put tests in assemblies apart from production code¶
The test must be placed in assemblies apart from code. Tests must never be shipped to production environments. Sometimes they requires dependencies that we don't want in final deployments. By separating test assemblies from production code we will be able to manage the dependencies as we need without make footprints in the production code.
Place related unit tests in individual files¶
Each component being tested should be placed in its own file, keep those tests next each other to facilitate its localization.
Use Skip
attribute for temporarily disabled tests¶
Sometimes you need to disable some tests for some reason, the best way to make
the tests don't run for a while is to mark them as skipped
using the Skip
attribute. Don't comment out the failing test because that way you won't realize
which of them needs to be worked out to bring them alive again, use Skip
attribute instead.
By using Skip
attribute you'll be able to clearly identify those skipped tests
among failed and succeeded ones, and due to the fact that the attribute requires
a reason as mandatory, you will get enough information to act on.
C# | |
---|---|
Parallelism in xUnit¶
How does xUnit.net decide which tests can run against each other in parallel? It
uses a concept called test collections
to make that decision.
By default, each test class is a unique test collection
. Tests within the same
test class will not run in parallel against each other. It means that, by
default, xUnit
runs tests in different test classes in parallel, which can
significantly shorten the time to run all your tests. It also means that xUnit
effectively ignores the Run Tests in Parallel
setting at the top of the Test
Explorer window
.
You can, however, override this default behavior where you need tests in
different classes to run sequentially by assigning test classes to the same
collection. You assign tests to a collection using the Collection
attribute,
passing a name for the collection.
C# | |
---|---|
By using the same test Collection
attribute we can tell the TestRunner
to
run methods in different classes to run sequentially.
There are more advanced options that can be used to particularize your test fixtures, that can be seen here.
Sharing context¶
Test context can be shared by three main mechanisms:
Constructor
andDispose
(shared setup/cleanup code without sharing object instances)Class Fixtures
(shared object instance across tests in a single class)Collection Fixtures
(shared object instances across multiple test classes)
Constructor
and Dispose
¶
xUnit.net creates a new instance of the test class for every test that is run, so any code which is placed into the constructor of the test class will be run for every single test.
When to use: when you want a clean test context for every test (sharing the setup and cleanup code, without sharing the object instance).
Remember to implement IDisposable
pattern to free up any resource allocated.
Class fixtures
¶
When to use: when you want to create a single test context and share it among all the tests in the class, and have it cleaned up after all the tests in the class have finished.
When using a class fixture
, xUnit
will ensure that the fixture instance will
be created before any of the tests have run, and once all the tests have
finished, it will clean up the fixture object by calling Dispose
, if present.
Collection Fixtures
¶
Sometimes you will want to share a fixture object among multiple test classes.
You can use the collection fixture feature of xUnit
to share a single object
instance among tests in several test class.
When to use: when you want to create a single test context and share it among tests in several test classes, and have it cleaned up after all the tests in the test classes have finished.
Please follow up this link for further reading.
Comparing xUnit with NUnit¶
These are some major changes made during the evolution from NUnit to xUnit:
- Single Object Instance per Test Method.
- No
SetUp
orTearDown
methods available, - No
ExpectedException
, useAssert.Throws
instead. TestFixture
was removed entirely; tests can be in any public class.Ignore
is expressed using theSkip
= parameter onFact
orTheory
.SetUp
andTearDown
are removed in favor ofConstructor
andIDisposable
.TestFixtureSetup
andTestFixtureTearDown
are removed in favor of implementing reusable fixture data classes, which are attached to test classes by having them implementIUseFixture<T>
.
A more detailed comparison of xUnit
to other frameworks can be seen
here.