0

I run unit and integration tests on my system. These create, start, stop and delete Docker containers. I want the exact same state in my Docker environment at the end of the tests as I had at the beginning. What would be the best way to restore the original state after the tests run?

Option A: I create a class in the main code that stops and deletes docker containers that were created and executed by the app, which is then also used by the tests.

Option B: I have an abstract class/interface in my main code which is extended/implemented by all classes that need to stop and delete. I create an extra class/method in test code which stops and deletes docker containers.

Option C,D,E,...: ???

Broader questions:

In general, does it make sense to create classes in the main code that are specifically designed to be used within the tests, but also by the main code. In my example: classes that can be used after testing to clean up the Docker environment, but also in the main code for the same purpose. Or should this be separated, even if this results in duplicate code when implemented in main and test, but the implementation in main code would be cleaner (e.g. better OO style)?

Is there anything against creating classes/methods in the main code that are mainly used for tests?

4
  • Do you create and destroy a container for every test? Jun 9 '21 at 12:50
  • For all docker related tests, yes. Destroy before and after each test in case something goes wrong and create before the test immediately after executing the destroy method.
    – slashleo
    Jun 9 '21 at 12:59
  • This means that you are possibly using the SetUp/TearDown methods (i.e. the methods that your test framework runs before and after every test), in which case, you would necessarily be using the option A. Isn't it? Jun 9 '21 at 13:02
  • This as shown would be an option. But I could also have these methods inside the test code and my questions is which does make more sense?
    – slashleo
    Jun 9 '21 at 13:10
2

Since you're creating a Docker container every time you run a test, and destroy it once the test is finished, the code which creates and destroys the container is, I imagine, in the SetUp/TearDown methods.

What you should consider is how different are those SetUp/TearDown methods from class to class.

  • If all they do is to call a method which would create/destroy the container, go with the base class option. This way, you'll put SetUp/TearDown methods in the base class, and avoid a small duplication.

  • If some classes require additional setup, then you may consider the other approach.

In both cases, if creating/destroying a container takes more than one line, consider putting the code in a separate class. It doesn't make sense to put all the creation/destruction logic in the test class, because it doesn't belong there. Your test classes should look like this:

class SomeIntegrationTests:
    def setUp():
        testContext.container = docker.create()

    def tearDown():
        docker.destroy(testContext.container)

    def testSomethingHere():
        ...

    def testOtherThings():
        ...

does it make sense to create classes in the main code that are specifically designed to be used within the tests, but also by the main code?

Absolutely. Your integration tests, when they test a specific part of your code, can rely on other parts which they don't test.

You should be careful, however, that if the code that your tests rely on misbehaves, it may fail those tests as well, but it usually won't be easy to identify the root cause.

Is there anything against creating classes/methods in the main code that are mainly used for tests?

Define mainly.

Production code should be limited to things that you need in production. If a piece of code is needed exclusively in tests, it doesn't belong to production code: move it to the test project. If a piece of code is used in production, but also by the tests, you're fine.

2
  • So if I undestand this right: Having a concrete class 'Destroyer' with a 'destroyContainer()' method in the main code which is then used inside the setUp/tearDown methods in testing is preferable to an interface 'Destroyer' with an equal method which is implemented by class 'ContainerA', 'ContainerB', etc., and an additional 'Destroyer' class inside the test code?
    – slashleo
    Jun 9 '21 at 13:48
  • That's correct. If the code is the same, don't duplicate it for the sake of duplication. Jun 9 '21 at 13:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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