Question

I have an integration test that needs to tweak some values on the database. This sort of tweak is not needed for the real application, only to setup the test scenario.

The dilemma:

Should I manipulate the DB directly from within the test project (by running a custom SQL query or by adding EF to the test project), or should I add fine-grained methods to the BL/Domain model/DAL that have no real purpose other than helping those integration tests? Is there a better way to achieve this?

Was it helpful?

Solution

This isn't a dilemma. There is no reason to contort yourself in order to avoid methods for testing.

Your test suite is a vital component of the code base - the fact that it isn't shipped to the customer is irrelevant. All best practices that are appropriate for business code are still appropriate for test code as well. Therefore, if the reasonable solution to accomplish something in a transparent, efficient and maintainable way is to create a method for it, then create that method. Whether or not that method ever runs in production should not be a factor in that decision.

OTHER TIPS

Generally, fixture setup through public API is preferable. If this is not the case, having some direct db access as testing backdoor is also acceptable. Alternatively, we also can use Prebuilt Fixture, there are lots of way to do it such as sql populating, data pump, etc. All of these fixture setups have the same challenge - fixture tear down. Automated Teardown may help for the case setting up and tearing down through API. For Prebuilt Fixture, maybe you should use some database flashback mechanism.

Another thought is, though in your question, you assume integration test should through database. However, it's not necessary always the case. Due to the difficulty of the setup and tear down, we should always try to humble it. If your code already has repository pattern, you can just implement an in-memory hash map for data store. The beauty of this is you can rely on Garbage-Collected Teardown. If this is not the case, try using in-memory database, then you also don't need to clean up the data created by your tests.

If the data is only required for a specific test, this is generally achieved via a transaction which is rolled back at the end of the test. C# has TransactionScope for this purpose. I daresay other languages have similar constructs.

The benefit of this approach is that you don't need to concern yourself with tear-down. You just set up the data (arrange), do the test (act) and check the test has worked (assert). This becomes super-important should the test be inadvertently run on a live database (yes, I've seen it happen!).

Licensed under: CC-BY-SA with attribution
scroll top