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 Answers4

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.

Bart van Ingen Schenau
  • 71,712
  • 20
  • 110
  • 179
  • interesting, different answer from Phillip above –  Sep 30 '20 at 06: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. – Bart van Ingen Schenau Sep 30 '20 at 07:01
  • Absolutely what Bart says - your `BeforeTest` function will often be `var testDataForThisTest = staticDataSet.copy()` or equivalent. – Philip Kendall Sep 30 '20 at 07: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?" –  Sep 30 '20 at 07: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 Sep 30 '20 at 15:42
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).

Philip Kendall
  • 22,899
  • 9
  • 58
  • 61
  • 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? –  Sep 30 '20 at 07: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 Oct 05 '20 at 09: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 Oct 05 '20 at 14:33
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.

0

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.

Ryathal
  • 13,317
  • 1
  • 33
  • 48