1

I decided to take the plunge and add the first set of integration and units tests to the projects I work on (yes, we have dozens of internal applications with no automated testing whatsoever...).

I really like the so-called behaviour driven conventions for naming: Given-When-Then, although the resources online are quite vague when applying it to the project structure, so I'm unsure how to apply it in a maintainable way.

For instance, at the moment it's like this:

- Test project

--- IntegrationTests (dir)
------ GivenAHomeController (dir)
--------- WhenAcknowledgingAnUrgentResult.cs
--------- WhenViewingAnUrgentResult.cs
--------- WhenViewingUrgentResults.cs

--- UnitTests (dir)
------ GivenAResultToAcknowledge (dir)
--------- WhenAcknowledgementTypeIsNone.cs

With an example unit test:

[TestClass]
public class WhenAcknowledgementTypeIsNone
{
    [TestMethod]
    public void ThenReturnWithModelStateError()
    {
        ...
    }
}

This way seems to follow that I've semantically locked it to having a separate class for every test case containing only a single test method. Should the test class be more generic with each test method including more of the "when"?

5
  • I'll be honest, this is the first time I've heard of a structure like this. Wouldn't it be more useful to have the test class be the GivenAHomeController with test methods WhenAcknowledgingAnUrgentResult() etc.? Do you have a link that provides more information on the approach? Apr 27, 2017 at 13:37
  • That does sound better yes. I got the idea from here: danylkoweb.com/Blog/… but after implementing it, it doesn't sit right, as you pointed out having the class name define the opening conditions seems more appropriate. It works ok with integration tests but it's just because they encapsulate much more, it's when it's applied to unit tests it's usefulness is diminished.
    – Lee
    Apr 27, 2017 at 13:46
  • There's also Martin Fowler's take on it but he speaks of the concept, not applying it structurally: martinfowler.com/bliki/GivenWhenThen.html
    – Lee
    Apr 27, 2017 at 13:55
  • My problem with this naming convention is that it doesnt work with data driven tests
    – Ewan
    May 1, 2017 at 7:29
  • @Ewan can you show me a better alternative i.e. the one that works for you/your team? And can you elaborate on data driven? Our team have quite like behaviour driven testing.
    – Lee
    May 2, 2017 at 8:20

1 Answer 1

1

I find the best structure, if you can call it that is,

Library
LibraryTests
    ClassATests.cs
    ClassBtests.cs



public class ClassATests
{
    [TestCase(1, 2, Category="Integration")]
    [TestCase(3, 4, Category="Unit")]
    public void MethodC(int input, int expectedResult)
    {
        //SetUp
        //create unit or integration setup of object under test
        Console.Write("given " + input);
        //Call
        Console.Write("when whatever");
        //Assert
        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

1
  • Some excellent points there that I had not considered. You've given me a good deal to think about, thanks.
    – Lee
    May 2, 2017 at 9:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.