6

I have a test with 15-20 different test cases, I want to run the same test with twice with two different parameters which are supposed to be passed to the test's BeforeClass method, for instance:

public class TestOne { private static ClassToTest classToTest; @BeforeClass public static void setUp() throws Exception { classToTest = new ClassToTest("Argument1", "Argument2"); } @Test public void testOne() { ........roughly 15 - 20 tests here } public class TestTwo { private static ClassToTest classToTest; @BeforeClass public static void setUp() throws Exception { classToTest = new ClassToTest("Argument3", "Argument4"); } @Test public void testOne() { ........roughly 15 - 20 tests here, same as in TestOne } 

As you can see the only difference between these two tests is in the setup method, which passes different values to the constructor of the ClassToTest. I don't want to replicate the test methods in both classes, but would prefer either inheritance or some other intelligent way to achieve this in one class.

1
  • Simple inheritance should work fine. Have you tried moving ClassToTest and testOne() to a baseclass? Commented Mar 29, 2012 at 16:35

5 Answers 5

6

This seems like a perfect use case for JUnit4's @Parameters; see https://blogs.oracle.com/jacobc/entry/parameterized_unit_tests_with_junit or http://www.mkyong.com/unittest/junit-4-tutorial-6-parameterized-test/ . That said, you'll have to move the initialization from the setUp method to a constructor for the test class.

Sign up to request clarification or add additional context in comments.

4 Comments

This is no good for me as we want only one instance of ClassToTest, it is very heavy object to create. I don't want my test to run forever. I mean one instance of ClassToTest, shared by all the test methods, that's why it is defined in the @BeforeClass
If your test class is really heavyweight...well, there's your problem right there. Break up your tests until they're less heavyweight.
I am not saying my test class is heavy, the class I am trying to test is heavy as it makes connection to the external system, we can't do anything about it, in fact this test is integration test to verify that we get right data from that system.
Ewwwww. Hrrrrrm. ...I might have to suggest the evil workaround of keeping the class under test in a static variable, which would make the cost of test object creation down. Other than that, I don't believe there is a solution for you.
1

For what it's worth, here is how you would do it with TestNG:

public class TestFactory { @Factory public Object[] createTests() { return new Object[] { new ClassToTest("arg1", "arg2"), new ClassToTest("arg3", "arg4") }; } } public class ClassToTest { public ClassToTest(String arg1, String arg2) { this.arg1 = arg1; this.arg2 = arg2; } @Test public void testOne() { // use arg1 and arg2 } } 

Comments

1

Thanks all for your quick replies. This is how I did it finally

public abstract class Base { final HeavyObject heavy; protected Base(HeavyObject heavy) { this.param = param; } @Test public void test() { param.doSomething(); } @Test .............More tests here } public class FirstTest extends Base{ private static HeavyObject param; @BeforeClass public static void init() { param = new HeavyObject("arg1", "arg2"); } public FirstTest() { super(param); } } public class SecondTest extends Base{ private static HeavyObject param; @BeforeClass public static void init() { param = new HeavyObject("arg3", "arg4"); } public FirstTest() { super(param); } } 

Base is an abstract class which has all the tests and FirstTest and SecondTest create their own objects with different parameters and pass it to the abstract class to use it.

Comments

0

As per the documentation (http://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html):

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

Comments

0

How about this:

public class TestOne { private static ClassToTest classToTest1, classToTest2; @BeforeClass public static void setUp() throws Exception { classToTest1 = new ClassToTest("Argument1", "Argument2"); classToTest2 = new ClassToTest("Argument3", "Argument4"); } @Test public void testOne() { testOneImpl(classToTest1); testOneImpl(classToTest2); } public void testOneImpl(ClassToTest classToTest) { // exact samew as whatever your current testOne() test method is } .... } 

EDIT: Or to keep method count down:

public class TestOne { private static List<ClassToTest> classesToTest; @BeforeClass public static void setUp() throws Exception { classesToTest = new ArrayList<>; classesToTest.add( new ClassToTest("Argument1", "Argument2")); classesToTest.add( new ClassToTest("Argument3", "Argument4")); } @Test public void testOne() { for (ClassToTest classToTest: classesToTest) { ... same test content as before } } 

2 Comments

Remember we have around 20 tests, so 20 times * 2 methods, will need to be written
I figured your concern was with duplication of code, not count of methods. This way there is no duplication of code, a succinct expression of intent, separation of concerns, etc. Is it really that onerous to add another very short boilerplate method for every test method? Of course you could iterate a list of classToTest1 and classToTest2 in each test method if you want to keep method count down, and the list could be defined once in setUp.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.