The idea of the article arose after several lectures on how to write tests and how to use
xUnit . Everything can be individually read in detail. Here I collected general information about how well in practice all this is applied and followed up with links for further reference. The review was made according to version 2.0.
Code conventions
A common practice is to place all test projects in a separate folder. This applies to the structure of the folders on the disk, and to the folders in the solution. Practice is common precisely because of convenience. Also, the name of the project and the namespace completely repeat the tested module with the addition of the word Tests at the end (usually through a dot). For ease of searching for tests, all tests belonging to a certain class are placed in its class with tests. So a pair is obtained from the original class and the class with tests. The division between the unit, integration, load occurs either by categories or by the logic of the main system. This means that if the integration test cannot be attributed to one class (usually, this is so), then they are put into a separate assembly dedicated to the tested functionality. Or, for example, load tests can test the work of a certain method of one class. In this case, the test is placed in the doubles class. The structure of the tests themselves of any type corresponds to the style of AAA. We systematize the above:
- Project Location: Folder Tests
- Test project name: [ProjectName] .Tests
- Namespace: [Namespace] .Tests
- Class name with tests: [Class] Tests
- Pair 1-1 of class and test class
- Name of unit tests: BDD ( manual )
- Test Style: AAA (Arrange-Act-Assert)
Comparing xUnit with other frameworks
xUnit is one of the most popular frameworks today. I will not dwell on his description, but I will give a dry squeeze. If you have questions, write in comments, I will answer.
A little outdated information, however, is quite complete, is compared to
xUnit with other frameworks (MSTest, NUnit) . I want to note only the important differences:
- Exception checking is done with assertions, instead of attributes, which more closely matches the AAA style (Assert.Throws, Record.Exception). Inside, exceptions are caught by a try-catch block.
- Replacing special attributes with natural language features (constructor, IDisposable, IClassFixture, ICollectionFixture)
The rest of the possibilities are similar. xUnit is credited with very high customization flexibility, the ability to extend / change behavior, test execution, etc. But I didn’t have to do something in practice.
Fact, Theory and other concepts
Fact is a separate unit test that takes no parameters. Theory is a test that takes parameters, and there may be several scenarios. Fixture - a class for setting and clearing some context. The context is attached to the class with tests either using the IClassFixture interface or using the collection and the ICollectionFixture interface. A collection can include several classes with tests.
Example Fact and two Theory options:
public class TestSuite { [Fact] public void Should_do_somthing(){...} [Theory] [InlineData(20, 180, 80, ”good”)] [InlineData(20, 180, 50, ”bad”)] public void Should_measure_weight(int age, int height, decimal weight, string expected){...} [Theory] [MemberData(“AgeHeightWeightData”)] public void Should_measure_weight(int age, int height, decimal weight, string expected){...} public static IEnumerable<object[]> AgeHeightWeightData() { yield return new object[] {20, 180, 80, "good"}; yield return new object[] {20, 180, 50, "bad"}; } }
Slightly more details
here and
here .
Contexts and test execution
By default, tests in the same class and collection run synchronously. For example, if you use a shared resource when performing tests and this causes problems (for example, tests fail, because the resource is locked), then you can put such tests in one collection and the problem will go away, because concurrency will disappear. In general, the call stack and what happens looks something like this:
')
CollectionFixture: ctor - TestClass1 TestClass2 ClassFixture: ctor - TestClass1 TestClass1: ctor - Test1() - TestClass1: disposed - TestClass1: ctor Test2() TestClass1: disposed ClassFixture: disposed - TestClass2: ctor Test3() TestClass2: disposed CollectionFixture: disposed TestClass3: Test4() -
It is worth noting that when defining a collection, a marker class is used that is not created at all. Only classes attached with ICollectionFixture are created. Read more about this
here , and about parallelism
here .
Support CI
It is, however, not everywhere out of the box. In my favorite TeamCity everything is fine, because nothing to do. Worse in Jenkins because need to be confused with installing the plugin. But in the TFS dark forest. I could not find the imputed example of installing and running xUnit. I will be glad links. It remains to be launched by the MSBuild and NAnt scripts.