I find the best structure, if you can call it that is,
public class ClassATests
[TestCase(1, 2, Category="Integration")]
[TestCase(3, 4, Category="Unit")]
public void MethodC(int input, int expectedResult)
//create unit or integration setup of object under test
Console.Write("given " + input);
Console.Write("then" + result);
Obviously this is a simple example, you can improve it by having data driven names and stuff, but it has several advantages.
- You can run all the tests for a given library project easily
- You can run all the tests for a given class easily
- You can run the exact same test in both unit and integration flavours
- The console output will display in the test result, so you can get detailed info on failures
- Data Driven tests allow you to test many scenarios with the same code
- When changing an existing class its always obvious to the developer where the existing tests are and where they should add new tests.
The problems I find with complicated test structures, involving inheritance and GivenThenWhen naming is that it is usually a custom invented structure rather than a standard out of the box visual studio one.
This makes it inherently harder for a developer, who just has a small change to make or bug to fix to figure out how to add a new test. First they must understand your test system.
Additionally, once figured out there is often a large amount of code to write, new files and classes added etc before a new test can be added, as apposed to what might be a single line test case in the above design.
The GivenThenWhen naming of classes and methods, often only works with particular test runner setups. If you don't have that setup you'll just see a whole bunch of WhenXisY with no info on what is actually going on.
In short the benefit of seeing nice GivenWhenThen output is more than countered by the cost of extra coding and difficulty in writing new tests.
In a large code base over a few years you may find you end up with multiple invented test systems as people improve and change what is considered a good system over time. I've worked in places where they have used multiple languages as well as test frameworks, runners and mocking systems in different components.
'Knowing the test structure' is no longer a simple thing. You may have to crack out an unsupported version of ruby, find that gem bob wrote before he left that makes it work with c# and then check the old jiras to find out how to make it work with team city