0

Please see the code below:

Guid product1Guid = Guid.NewGuid();
Guid product2Guid = Guid.NewGuid();
Products = new List<Product>();
var product1 = new Product(product1Guid), "Product 1");
var product2 = new Product(product1Guid), "Product 2");
Products.Add(product1);
Products.Add(product2);

This code is used by five of my test methods. Where do I put this code? The options are:

1) OneTimeSetup method: An answerer of another question advises against this because Product is mutable and in the future one test could accidentally mutate the state meaning all the following tests fail.

2) Create a method inside the test class (which returns the list): An answerer of another question advises against this because you should not stub a simple data object.

3) Put the code above in each test method. This seems to violate the DRY principle.

4) Create a Helper class, which is external to the test class (which returns the list):. I am not sure if this is normal.

I realise that all of the options above will work. I am trying to follow the principle of least astonishment here so that Developers who look at my code in future will know what to expect.

w0051977
  • 15,099
  • 32
  • 152
  • 329
  • 1
    Depending on your test framework there will be an attribute `[TestInitialize]` which indicates, that the method will be executed before each test execution. Look at this example: https://stackoverflow.com/questions/26548017/unit-test-c-sharp-testinitialize – Sebastian Siemens Jan 23 '18 at 09:45
  • @Sebastian Schulz, thanks. I believe that answers my question. Is it normal to use this method to initialise lists (like in my case)? If you post an answer then I will give some credit. – w0051977 Jan 23 '18 at 09:48
  • @Sebastian Schulz , I am using NUnit by the way as tagged – w0051977 Jan 23 '18 at 09:49
  • The way how to implement depends on your project. if the objects you want to initialize are only used in one test class, I would use a method with the TestInitializeAttribute. If it is used in more than one testclass i would prefer to use a context object which will be initialized in a helper class called from a method with a testinitializeattribute. Option 1 and 3 are possible but i would not recomend them. – Sebastian Siemens Jan 23 '18 at 09:58
  • @Sebastian Schulz, thanks. Say I have an IEqualityComparer (a class with no state) that is used by all test methods. Would you declare this as an instance variable and initialise it i: OneTimeSetup ? – w0051977 Jan 23 '18 at 10:20
  • I think answers to other questions may not be applicable for your case, as there may differences in what the purpose of the common code, how the tests are built etc... It looks like any of the 4 solutions you've suggested may be valid - maybe you can add more background on your Unit Under Test, as well as the overall test structure? – Amittai Shapira Jan 23 '18 at 15:31

1 Answers1

2

NUnit SetUp attribute solves this.

This attribute is used inside a TestFixture to provide a common set of functions that are performed just before each test method is called.

[TestFixture]
public class ExampleTest
{
    Guid product1Guid;
    Guid product2Guid;
    List<Product> Products;

    [SetUp]
    public void PerTestPrepare()
    {
        product1Guid = Guid.NewGuid();
        product2Guid = Guid.NewGuid();
        Products = new List<Product>();
        var product1 = new Product(product1Guid), "Product 1");
        var product2 = new Product(product1Guid), "Product 2");
        Products.Add(product1);
        Products.Add(product2);
    }

    [Test]
    public void SimpleCheck_Containts_True()
    {
        Assert.IsTrue(Products.Any(p => p.Id == product1Guid));
    }
}
aleha_84
  • 8,309
  • 2
  • 38
  • 46
  • Good answer. Note that it implies that all of your tests use the same setup. That's perfect if you follow the principle that a TestFixture should contain all the tests that use the same setup. In practice, you can include tests that ignore the setup, of course. – Charlie Jan 23 '18 at 18:23