Tests and inheritance problem

Imagine that you have an application and you want to do unit tests and functional tests on it (it's not so hard to imagine). You may have an abstract class, let it be called AbstractTestClass, from which all of your unit tests are distributed.

AbstractTestClass will look something like this (using JUnit 4):

class AbstractTestClass { boolean setupDone = false; @Before public void before() { if(!setupDone) { // insert data in db setupDone = true; } } } 

This is what I'm fighting. I have another abstract class that checks web interfaces:

 class AbstractWebTestClass extends WebTestCase { boolean setupDone = false; @Before public void before() { if(!setupDone) { // here, make a call to AbstractTestClass.before() // init the interfaces setupDone = true; } // do some more thing } } 

This is almost the same class, except that it extends WebTestCase . This design can give me the opportunity to have the same data during unit testing than when testing the interface.

Usually, when dealing with such a problem, you should maintain composition over inheritance or use a strategy template.

Unfortunately, I don’t really like the idea of ​​composition over inheritance in this particular scenario, and I don’t see how I can use the strategy template, there is probably a design flaw and I can’t see the solution.

How can I design this architecture to achieve my goal.

+4
source share
3 answers

I would implement this as follows:

 class Example { class LazyInitStrategy implements Runnable { private final Runnable operation; private boolean done = false; LazyInitStrategy(Runnable operation) { this.operation = operation; } @Override public void run() { if (!done) { operation.run(); done = true; } } } private final class AbstractInit implements Runnable { public void run() { // insert data in db } } private final class AbstractWebInit implements Runnable { public void run() { // here, make a call to AbstractTestClass.before() init the interfaces } } class AbstractTestClass { final LazyInitStrategy setup = new LazyInitStrategy(new AbstractInit()); @Before public void before() { setup.run(); // do some more thing } } class AbstractWebTestClass extends WebTestCase { final LazyInitStrategy setupInfo = new LazyInitStrategy(new AbstractWebInit()); @Before public void before() { setupInfo.run(); // do some more thing } } 

}

Of course, this is a very simplified solution, but it should eliminate if / else is a logical duplication to check whether the installation was completed. Using Runnable is optional, I did it for demo purposes only, in the reading world you are likely to use a different interface.

+2
source

The important thing to do is not to duplicate the code. In this situation, I would create

MyScenarioTestUtil

which contains many static methods that tune data as needed. You must call the utilities from the settings. This way you save all the code in one place.

This is actually just a semantic difference from using composition ...

0
source

I think the design is not right at all. You should not use inheritance in unit tests at all. Testing should be isolated and really simple. Very often, as in your case, it is necessary to prepare some additional objects that will help test methods do their job. In this case, you should identify the builders of such objects and place them somewhere outside the test cases.

For instance:

 public void testMethodThatNeedsSomePreparedObjects() { Foo foo = new FooBuilder() .withFile("some-text.txt") .withNumber(123) .build(); // now we are testing class Bar, using object of class Foo Bar bar = new Bar(foo); } 

So you need FooBuilder define FooBuilder somewhere else, and this class will do all the work you are currently trying to do using a strategy template or inheritance. Both approaches are erroneous when working with unit tests.

0
source

All Articles