37

how can I reuse JUnit tests in another testclass?

For example:

public TestClass1 {
    @Test
    public void testSomething(){...}
}

public TestClass2 {
    @Test
    public void testSomethingAndSomethingElse() {
        // Somehow execute testSomething()
        // and then test something else
    }
}
tk2000
  • 581
  • 2
  • 5
  • 10
  • 4
    Unit tests should be independent/isolated. Making one test dependent on another is a bad idea. – xyz Jun 17 '13 at 09:51
  • 4
    @Karna: use case: your app/framework supports several databases. so you have one base test class which contains tests for all features and one extension per database which creates the connection, loads the initial DDL/data, etc. – Aaron Digulla Jun 17 '13 at 12:03
  • @AaronDigulla: Its a bad idea and sometimes being bad is good :) – xyz Jun 18 '13 at 06:04

4 Answers4

40

Avoid the scenario, in general. It is prone to making tests much more brittle. If TestClass1 fails, then TestClass2 implicitly fails, which isn't desirable for at least the following reasons:

  • Code is tested more than once, which wastes execution time.
  • Tests should not rely on each other, they should be as decoupled as possible
  • If this becomes a pattern, it will become harder to identify what section of code is broken by looking at which tests are failing, which is part of the point of tests

Occasionally sharing sections of test code is useful, particularly for integration tests. Here's how you might do it without depending on the tests themselves:

public abstract BaseTests {

    protected void somethingHelper() {
        // Test something
    }
}

public TestClass1 extends BaseTests {
    @Test
    public void testSomething(){
        somethingHelper();
    }
}

public TestClass2 extends BaseTests {
    @Test
    public void testSomethingAndSomethingElse() {
        somethingHelper();
        // and then test something else
    }
}

Alternatively, you could use a helper class and avoid the inheritance altogether. Asserts and the like can go in the somethingHelper() method.

Don't call a method from TestClass1 in TestClass2 directly. The test cases become less readable this way, and can lead to spaghetti frittata.

Dave Jarvis
  • 28,853
  • 37
  • 164
  • 291
seanhodges
  • 16,593
  • 14
  • 67
  • 89
  • 2
    What you said is true for unit tests cases. What about integration or functional test cases where child scenarios are dependent on parent scenarios and each siblings are independent on one another? – supertonsky Oct 02 '14 at 15:57
  • This question is tagged "unit-tests", but for integration or functional test cases the second half of my answer applies. Sections of test code can be shared for just this purpose. The key is to avoid calling one test directly from another, instead move the shared code into a base class or a helper. This makes it clear what sections of the test suite are shared. – seanhodges Nov 18 '14 at 10:22
  • I'm facing a scenario where I would like to ensure that specific Tests are still running and passing and that were not removed (the associated dev code change was to delete some of these components) Would you think this is a legit scenario where I could be calling onto existing tests and ensuring that they are still there and fine? Otherwise, they could have just deleted them by accident and the test suite wouldn't fail at all – Osmar Oct 03 '19 at 15:59
12

As usual you can:

  1. Extends TestClass2 from TestClass1
  2. Access TestClass1 from TestClass2 using delegation:

Example 1:

// Instantiate TestClass1 inside test method
public TestClass2 {
    public void testSomethingAndSomethingElse1() {
         new TestClass1().testSomething();
    }
}

Example 2:

// Instantiate TestClass1 as a member of TestClass2
public TestClass2 {
    private TestClass1 one = new TestClass1();
    public void testSomethingAndSomethingElse1() {
         one.testSomething();
    }
}
AlexR
  • 109,181
  • 14
  • 116
  • 194
4

This is common to run a test with a different configuration. Do not worry about and go ahead.

At the first step create your own test without considering any configuration:

public abstract BaseTests {
    @Test
    protected void somethingHelper() {
        // Test something
    }
}

Then, extend the test class and add some configuration:

public TestClass1 extends BaseTests {
    @Before
    public void setup(){
         // TODO: config
    }
}

It is not necessary to do specific configuration but it is very common with a configurable system (the main functionality of the system must be valid for each config).

In the other test case:

public TestClass2 extends BaseTests {
    @Before
    public void setup(){
         // TODO: other config
    }
}

For example, there may be an encryption and decryption process where the sequence of encryption>decryption must be identified. On the other hand, there is a different algorithm to use while the test process is unique.

Mostafa
  • 1,313
  • 16
  • 28
1

Logically, there is no reason to call one test method from another. Any tool that runs one test would just as easily all tests in the package. But if you need to, you'd call it like any other method in any other class.

What you most likely want to do, is perform some common setup for both test methods. You could put that code in a utility method in a common class, and invoke the common code in both tests.

Rajesh J Advani
  • 5,239
  • 1
  • 18
  • 32
  • use case: your app/framework supports several databases. so you have one base test class which contains tests for all features and one extension per database which creates the connection, loads the initial DDL/data. – Aaron Digulla Jun 17 '13 at 12:03
  • The pre-loading of data is a setup step. It should not be part of a test case, but a prerequisite for all test cases. – Rajesh J Advani Jun 17 '13 at 12:19
  • That's about 10% of what I was talking about. The test case will have many, many test cases that you need to run for every database which you need to support. There is no point in duplicating this code. – Aaron Digulla Jun 17 '13 at 12:22
  • I never said test cases need to be duplicated. I mean the relationship should be other than test cases calling each other. You could have different Test Suites that use the same test cases with a different set of prerequisites each. Otherwise the modeling is simply wrong. – Rajesh J Advani Jun 18 '13 at 11:39
  • My example is a perfect example for using OO to organize tests. No test suites, hacks or other magic needed. The abstract base test has an abstract `getConnection()` method and everything else is inherited. If a feature isn't support for a certain database, you can easily exclude it by overriding it. – Aaron Digulla Jun 18 '13 at 16:08
  • Oh, *that* is what you meant by *extension*. Yes, using an abstract base class works. My point was that "calling" is bad. The OP didn't say why they wanted to do this, so I was just replying to their specific question. – Rajesh J Advani Jun 19 '13 at 06:01
  • Another use case: I need to do this because I have a large amount of tests which access a database that is set up as a prerequisite. I am discovering that there may be dependencies between the test cases (and there shouldn't be) and am trying to isolate those dependencies so I'd like to run specific tests together without totally refactoring my project. This is simply a temporary debugging mechanism. – Kramer Aug 14 '17 at 14:28
  • @AaronDigulla this is a really good way to share test code between different implementations of code under test. And it is not only useful for databases. It allows all implementations of an interface to share tests. It allows you to establish that all implementation code conforms to the contract of an interface. – John Mercier Dec 03 '17 at 17:22
  • @JohnMercier If you're using interfaces, then you should consider using JUnit rules. – Aaron Digulla Dec 08 '17 at 14:17