1

We are writing application service tests across our Data Service Class.

Currently writing tests liking add Product, remove Product, check for inventory after sale, etc. They are all using the same data storage in a list, BeforeEach Method.

When they are all utilizing the same data set, I'm afraid changing one piece of data, will affect all the other unit test. Is that the proper unit test method, or should unit tests have their own data set or factory method?

    product.Add(
        new Product
        {
            ProductId= "1",
            Quantity= 5,
            Code= "Table",
        },
        new Product
        {
            ProductId= "2",
            Quantity= 7,
            Code= "Food",
        }

}

I understand, Unit Tests should not modify each others data. The question is even if they have same data setup clones in individual memory sets, changing the common data setup can affect other test results, which still leads to tightly coupled. Is this good practice?

4 Answers 4

3

I think you already know the answer to this - shared data is a bad idea, for exactly the reason you state: if one test modifies the shared data, then it can affect the behaviour of all your other tests. We want our unit tests to be independent, both so we can run them individually if we need to, and so that we don't have "cascading" failures from one test to another where tests fail because we changed some unrelated code.

Your test framework almost certainly has a BeforeTest/SetUp method which is run before every test and is exactly the place to create the test data for every test. (If your test framework doesn't have this kind of method, get a better test framework).

3
  • clarified question with this comment, "I understand, Unit Tests should not modify each others data. The question is even if they share same data setup in individual memory sets, changing the data setup can affect other test data setups, which still leads to tightly coupled. Is this good practice?
    – user375708
    Commented Sep 30, 2020 at 7:10
  • It's quite simple. Each test builds (or asks for someone else to build'em) new fresh and independent datasets which reproduce the scenario under test. E.g, ProductsDSL.createSoldProducts(). No factory method shares common setup/data unless those are immutable. In other words, run away from "global states" when coding unit tests. The BeforeTest/SetUp mechanisms should not be used to prepare data, they are rather here to configure o pre-configure the elements related to the code under test, but they are a terrible place where to prepare the testing scenarios.
    – Laiv
    Commented Oct 5, 2020 at 9:43
  • @MarkThomas52: There's a difference between multiple tests depending on a specific (shared) data setup, or providing a default data setup that each test can choose to use or (alternatively) supply its own setup logic. Favor the second, as it provides the best of both worlds: not needing to reinvent the wheel for every test, but the ability to reinvent it when intentionally chosen to do so.
    – Flater
    Commented Oct 5, 2020 at 14:33
3

When you are testing a unit that uses a datastore, you should ensure that the datastore you use for testing gets completely re-initialized before each test. That ensures that the current test cannot be affected by changes made to the datastore by the previous test.

If you have multiple tests that don't place particular conflicting requirements on the data set contained in the datastore, then it is entirely valid to create a common method that gets used to reinitialize the datastore for those tests with the same set of test data. The advantage here is that if the structure of the data changes (e.g. a field gets added), then you have to update fewer places in your test code to fill the datastore with valid data.

If you really change the contents of your common data set, like you remove the Product with id 1 from it and instead add a Product with id 3, then you have to inspect all testcases that use that data set if they need to be updated to work with the new data set. That is the drawback of re-use and a reason why such changes to a common data set should not be made lightly. If you find yourself making such changes frequently, you should seriously consider using dedicated data sets for each testcase.

5
  • interesting, different answer from Phillip above
    – user375708
    Commented Sep 30, 2020 at 6:51
  • 1
    @MarkThomas52, the answers are not that different. We both say that data must not be shared between tests, but the datastores of different tests can be filled with a copy of the same initial dataset. Commented Sep 30, 2020 at 7:01
  • Absolutely what Bart says - your BeforeTest function will often be var testDataForThisTest = staticDataSet.copy() or equivalent. Commented Sep 30, 2020 at 7:08
  • I left one more comment to clarify, not sure if this changes, answer, "I understand, Unit Tests should not modify each others data. The question is even if they have same data setup clones in individual memory sets, changing the common data setup can affect other test results, which still leads to tightly coupled. Is this good practice?"
    – user375708
    Commented Sep 30, 2020 at 7:12
  • @MarkThomas52: you will probably become a better programmer when you stop thinking in terms of unconditional "good practices". There is no braindead cargo-cult rule to follow here. Instead, read the answer again, it says "under conditions X0 this could be a good idea, since it has advantages Y, but under conditions X1, it has also drawbacks Z". It is up to you to check which conditions apply to your case.
    – Doc Brown
    Commented Sep 30, 2020 at 15:42
1

Tests using the same base data is fine. Tests relying on data being modified from other tests would be a red flag. Tests all using different test data is ok as well.

If modifying the base data for your unit tests causes mass failure, that can be a good thing. Your tests may not be as valuable as you thought, weren't testing all cases, or weren't properly testing the code. If you use totally isolated data for each test you may never discover that feature A was broken by feature B until you reach production.

Writing tests that never fail isn't the goal of tests, tests that always fail are similarly bad. You want test that fail when things change that are important to that test.

0

It depends. That said, I would like to see the data required to run a unit test as either reference and operational. For example, if I am working on a shopping cart part of an application - I need to have some products available. The reference data for a unit test, might be operational for some other tests and vice versa.

My suggestion will be to keep reference data that can be shared among the unit tests and each unit test creates and owns its operational data.

Your Answer

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