1

I have just started learning JUnit very recently and came across the following problem.

Have a look at the following class

class MyClass { String a; public MyClass(String a) { this.a=a; String doSomething(String a) { if( a.isEmpty() ) return "isEmpty"; else return"isNotEmpty"; } 

I want to test the above method for both the conditions. If I proceed with the general structure of writing testcases it will look something like this:

class MyClassTest { MyClass myClass; @BeforeEach void setUp() { myClass=new MyClass("sampleString"); } @Test void doSomethingTest() { Assertions.equal("isNotEmpty", myClass.doSomething()); } } 

However, for testing the empty string condition I will need another setup method where instead of "sampleString" I pass an empty string.

Following are the approaches I could think of and the questions for each:

  • Not use setUp at all and instead initialize the class in the individual test method. However, if let's say there are 10 testcases; 5 of which require empty string and rest "sampleString" then this doesn't make sense. Again, we can have a separate method for this repetitive code and call it individually in each testcase but then that defeats the purpose of having a steup method. Lets say I wanted to use two different setup methods, is there a way to do so?
  • Have a parameterized setup. I don't know if this is possible though. If yes, please share some useful links for this.
  • Use TestFactory. I tried reading up about this, but couldn't find an example for this specific case. If you have any, please share.

This example has been kept simple for illustrative purposes.

3
  • Have you considered distinct classes for every setup, or this option is not walkable ? Commented Apr 22, 2020 at 12:21
  • Link to parameterized tests in Junit 5 Commented Apr 22, 2020 at 12:35
  • Take a look at @org.junit.jupiter.api.Nested test classes for complex setup scenarios, they may contain @BeforeEach test setup methods too. Commented Apr 22, 2020 at 12:49

2 Answers 2

3

Group the tests with the same setup in an inner class annotated with @Nested. Each nested test class can have its own setup in a local @BeforeEach method.

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

Comments

1

You can always prepare the non-common data inside your test method. I've always thought it's easier this way, compared to using parameterized tests. You can't mix parameterized and non-parameterized tests in 1 file.

@Test void doSomething_nullString() { myClass = new MyClass(null); Assert.assertNull(myClass.doSomething()); } @Test void doSomething_emptyString() { myClass = new MyClass(""); Assert.assertEquals("", myClass.doSomething()); } @Test void doSomething_nonEmptyString() { myClass = new MyClass("sampleString"); Assert.assertEquals("sampleString", myClass.doSomething()); } 

Or, you can always have helper methods inside the test class.

private MyClass createTestObject_nonNullString() { return new MyClass("nonNullString"); } private MyClass createTestObject_nullString() { return new MyClass(null); } @Test public void doSomething_sample() { MyClass test = createTestObject_nonNullString(); // perform test } 

6 Comments

This is useful if the constructor initializations and setup is simple. However, consider a case where the class used for 5 tests has the same constructor and setup steps; and the remaining 5 tests have a similar class and setup. What should be the approach then?
@kernel0707 I've updated my answer. Maybe there are better approaches, but this is how I usually do it.
I had a look at your solution after submitting this comment. Editing and keeping it for others to see. Above solution works. :) What if the class has several methods and each behaves differently based on whether the string is empty or not. How to test both sets of behavior? Another real-life example could be let's say I have a class with an array as a member variable. Each method of this class gives some output based on the array and throws an expcetion if array is empty. So how should I test each method first for the general behavior, and then for the case where the exception is thrown.
@kernel0707 I can see your excitement, but I'm not exactly sure how to answer all your question. I would suggest to find some online course about JUnit, so you can learn the basics of unit testing. Later, you will need to use other libraries like Mockito (or EasyMock), which will help you mock the behavior of dependencies/interfaces that are used in your code. For exceptions, there's a way to test that too - like this: guru99.com/junit-exception-test.html
Why can’t you mix parameterized with normal tests in one file? Although I don’t see how parameterized would test help for the given question at all.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.