How to link #BeforeEach method with specific #Test methods (Java, JUnit)? - java

For example we have 2 classes: BaseTest and Test. Test extends BaseTest.
BaseTest.class contains 2 methods with #BeforeEach annotations.
#BeforeEach
void setUp1() {}
#BeforeEach
void setUp2() {}
Test.class contains 2 methods with #Test annotations.
#Test
void test1() {}
#Test
void test2() {}
Is there a way to link the #BeforeEach method with #Test method, so the setup1() would run only before test1() and the setup2() would run only before test2()?

You can't really do this, but you can bundle Testcases with with #Nested classes.
public class Test {
#BeforeEach
void setUpForAll() {}
#Nested
class TestCasesWithPrecondition1{
#BeforeEach
void setUp1() {}
#Test
void test1() {}
}
#Nested
class TestCasesWithPrecondition2{
#BeforeEach
void setUp2() {}
#Test
void test2() {}
}
}

A distinct non-answer: don't do that!
The purpose of your unit tests is to help you to identify breakages in your production code quickly. Thus a base rule is: keep a very simple structure.
One aspect of a good unit test is: you look at the test method, and you know what is going on. If at all, you have to scroll to some setUp() method above (same file!) to see what is going on.
What you intend to do requires that future readers not only have to know about that base class, they also have to understand that there is some complex logic in play that uses different mechanisms per test method.
So, yes, avoiding code duplication is important for unit tests, too. But you avoid "getting there" by applying the same patterns that you use for your production code.

Related

About unit-test dependency

I'm trying to code some basic unit-tests for a project I am currently working on where I have my service that has a method addPlaneModel to add a plane model (under the hood it adds a PlaneModel instance into a TreeMap and throws a custom exception if the TreeMap already contains the key).
I could write a test (for example shouldAddNewPlane_Succeed) to see if it's properly adding the PlaneModel but my problem comes if I wanted to create a test to see if the PlaneModel already existed (for example shouldAddNewPlane_ThrowExistingModelException because I should call addPlaneModel twice to make it throw the exception, but if shouldAddNewPlane_Succeed test doesn't run first, I don't really 'know' if that method works as it should.
I've read that unit-tests should be independant from each other but I can't really grasp how to do it in this case, do I necessarily have to run them in order?
You should be creating a new instance of the class you are testing before each test.
So your test class will look like:
class MyTests {
private MyService myService;
#Before // junit 4, or #BeforeEach for junit 5
public void setup() {
myService = new MyService(... pass mocks of dependencies ...);
}
#Test
public void aTest() {
myService...
}
#Test
public void aTest2() {
myService... // this is a fresh instance of MyService, any changes to the
// state of the instance used in aTest() are gone.
}
}
If you want to execute some common code before running a test, you can use the #Before method annotation in JUnit. For instance:
#Before
public void init() {
LOG.info("startup");
list = new ArrayList<>(Arrays.asList("test1", "test2"));
}
This code will always execute before any other test that you run. This is useful to define a certain order for execution to your tests.

How to reuse method and test in JUnit?

I've tried to avoid duplicate code in JUnit test, but I'm kind of stuck.
This is my first test, for the second one it has exactly the same methods but different service (different input). instead of the TestCaseResourceTest1 I have TestCaseResourceTest2. Now what could be the proper way to test both? I want to have a separate file for test number 2, how should I avoid the duplicate code? (ex. use the beforeFileTest() method)
public class TestCaseResourceTest1 {
#Mock
private TestService testService;
#Mock
private AreaService areaService;
private TestCaseService1 testCaseService1; // is changed in test2
#Before
public void before() throws Exception{
testCaseService1 = mock(TestCaseService1.class); // is changed in test2
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
private void beforeFileTest() throws Exception{
doReturn(true).when(areaService).chechExists(any(String.class), eq(false));
}
#Test
public void verifyFileExists() throws Exception{
verifyOtherArea(testCaseService1); // is changed in test2
doReturn(false).when(areaService).chechExists(any(String.class), eq(false));
}
}
just lines with comment is changed in test2 are differences.
Tnx
Given this excerpt from your question:
… instead of the TestCaseResourceTest1 I have TestCaseResourceTest2 … I want to have a separate file for test number 2
… the standard ways of sharing code between test cases are:
Create a Test Suite and include the shared code in the test suite (typically in #BeforeClass and #AfterClass methods). This allows you to (1) run setup code once (per suite invocation); (2) encapsulate shared setup/teardown code and (3) easily add more tests cases later. For example:
#RunWith(Suite.class)
#Suite.SuiteClasses({
TestCaseResourceTest1.class,
TestCaseResourceTest2.class
)}
public class TestSuiteClass {
#BeforeClass
public void setup() {
beforeFileTest();
}
private void beforeFileTest() throws Exception {
// ...
}
}
Create an abstract class which parents TestCaseResourceTest1 and TestCaseResourceTest2 and let those test cases call the shared code in the parent (typically via super() calls). With this approach you can declare default shared code in the parent while still allowing sub classes to (1) have their own behaviour and (2) selectively override the parent/default behaviour
Create a custom JUnit runner, define the shared behaviour in this runner and then annotate the relevant test cases with #RunWith(YourCustomRunner.class). More details on this approach here
Just to reiterate what some of the other posters have said; this is not a common first step so you may prefer to start simple and only move to suites or abstract classes or custom runners if your usage provides a compelling reason to do so.
I had the such situation and it was a sign about wrong implementation design. We are talking about pure unit tests where we test exactly what is implemented in the production classes. If we need duplicated tests it means we probably have duplication in implementation.
How did I resolve it in my project?
Extracted common logic into parent service class and implemented unit tests for it.
For child services I implemented tests only for particular implemented code there. No more.
Implemented an integration tests on real environment were both services were involved and tested completely.
Assuming you want to have the exact same test run for 2 different classes (and not mocking it as in your example code), you can create an abstract test class, that has abstract method that returns an instance of the class to be tested.
Something in the vein of:
public abstract class TestCaseResourceTest {
protected abstract TestCaseService1 getServiceToTest();
#Before
public void before() throws Exception {
testCaseService1 = getServiceToTest();
MockitoAnnotations.initMocks(this);
beforeFileTest();
}
#Test
public void test() {
// do your test here
}
}
public class ConcreteTest extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new TestCaseService();
}
}
public class ConcreteTest2 extends TestCaseResourceTest {
protected TestCaseService1 getServiceToTest() {
return new DifferentService();
}
}
Have you considered using JUnit 5 with its http://junit.org/junit5/docs/current/user-guide/#writing-tests-parameterized-tests ?
It allows you to re-use your tests with different input. This is an example from the documentation which illustrates what you can do now with JUnit 5:
#ParameterizedTest
#ValueSource(strings = { "Hello", "World" })
void testWithStringParameter(String argument) {
assertNotNull(argument);
}
But you can also create your methods which return the input data:
#ParameterizedTest
#MethodSource("stringProvider")
void testWithSimpleMethodSource(String argument) {
assertNotNull(argument);
}
static Stream<String> stringProvider() {
return Stream.of("foo", "bar");
}
Here I am using just strings, but you can really use any objects.
If you are using Maven, you can add these dependencies to start using JUnit 5:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.0.0-RC2</version>
<scope>test</scope>
</dependency>
The only annoying thing about JUnit 5 is that it is not released yet.
When going from one test to two tests, you don't know what will be duplicate code, so I find it useful to put everything into one test method. In this case, start by putting the contents of the #Before and beforeFileTest methods inline in the test.
Then you can see that it is just te service that needs changing, so you can extract everything except that into a helper method that is called from two tests.
Also, after you have two tests that are calling the same helper method and are happy with that test coverage, you could look into writing parameterized tests. For example with JunitParams: https://github.com/Pragmatists/junitparams/wiki/Quickstart

how to initialize JUnit test classes before running in parallel

I am trying to execute JUnit tests in parallel using the ParallelComputer experimental feature, however I do not know how to pre-initialize each of the test classes before kicking off the tests.
The classic example of how these are supposed to be used is as follows (as shown in the following GitHub link). Per the example, how do I initialize the ParallelTest1 and ParallelTest2 classes with shared data before starting the parallel thread testing. I was able to do this via constructors in each of the classes, however I need to make sure that both classes are fully initialized before the run starts. This problem is probably not specific to the Parallel nature of how I wish to perform the testing but more likely how to use some special keywords to order prevent initialized objects from starting until required. Ideally the example ParallelComputerTest could have this shared data initialized in its constructor, however in that case, how could the nested static parallel test classes get access to this instance data?
public class ParallelComputerTest {
#Test
public void test() {
Class[] cls={ParallelTest1.class,ParallelTest2.class };
//Parallel among classes
JUnitCore.runClasses(ParallelComputer.classes(), cls);
//Parallel among methods in a class
JUnitCore.runClasses(ParallelComputer.methods(), cls);
//Parallel all methods in all classes
JUnitCore.runClasses(new ParallelComputer(true, true), cls);
}
public static class ParallelTest1{
#Test public void a(){}
#Test public void b(){}
}
public static class ParallelTest2{
#Test public void a(){}
#Test public void b(){}
}
}
Use #Before for set ups and #After for clean ups.
For example to test console output I set up streams before and clean result after test like this:
#Before
public void setUpStreams() {
System.setOut(new PrintStream(outContent));
System.setErr(new PrintStream(errContent));
}
#After
public void cleanUpStreams() {
System.setOut(null);
System.setErr(null);
}
NOTE: this can cause problems with TestSuite, dunno if also with ParallelTest. If you experience some troubles AND you use JUnit 4.7 or higher you might like to check this link to rules feature

Junit Jmock testing: multiple #Before for tests

I am not sure if it is possible to do, but I need to call different #Before methods depending on Tests. Is it possible, to make some resolver for it?
#Before
performBeforeOne();
#Before
performBeforeTwo();
#Test
callBeforeOneAndExecuteTestOne();
#Test
callBeforeTwoAndExecuteTestTwo();
Or should I just create several methods and call them manually from each test?
No, you can only have one method with each lifecycle annotation. Create a composite method that calls the others if they're too large to combine.
I think the best way to achieve this (and the clearest) is to refactor your tests as such:
#Before
public void performBeforeForAll() {}
#Test
testOne() {
testOneBefore();
//.. test execution
}
#Test
testTwo() {
testTwoBefore();
//.. test execution
}
private void testOneBefore() {}
private void testTwoBefore() {}
That way, you can see exactly what each test is setting up before it runs. You will probably find that some tests share the same setup code, in which can you have a private method already there to prevent duplication.

JUnit TestCase object instantiation

Is a new (or different) instance of TestCase object is used to run each test method in a JUnit test case? Or one instance is reused for all the tests?
public class MyTest extends TestCase {
public void testSomething() { ... }
public void testSomethingElse() { ... }
}
While running this test, how many instances of MyTest class is created?
If possible, provide a link to a document or source code where I can verify the behaviour.
Yes, a separate instance is created.
While running that test, 2 instances of MyTest gets created.
If you want a different behavior, one option is to use a similar tool called TestNG(http://testng.org/doc/).
I couldn't find a clear answer in the JUnit docs about your question, but the intent, as anjanb wrote, is that each test is independent of the others, so a new TestCase instance could be created for each test to be run.
If you have expensive test setup ("fixtures") that you want to be shared across all test cases in a test class, you can use the #BeforeClass annotation on a static method to achieve this result: http://junit.sourceforge.net/javadoc_40/org/junit/BeforeClass.html. Note however, that a new instance may still be created for each test, but that won't affect the static data your #BeforeTest method has initialized.
There's one instance for each test run. Try
public class MyTest extends TestCase {
public MyTest() { System.out.println("MyTest Constructor");
public void setUp() { System.out.println("MyTest setUp");
public void tearDown() { System.out.println("MyTest tearDown");
public void testSomething() { System.out.println("MyTest testSomething");
public void testSomethingElse() { System.out.println("MyTest testSomethingElse");
}
The Sourcecode (including that to newer versions - your and my example is Junit 3) is on http://www.junit.org
If you are asking this because you are concerned about data being initialized and re-initialized in your constructor, be aware that the prescribed way to initialize your test cases data is via setUp() and tearDown() exclusively.
Yes, definitely. I found that data I stored in instance variables could not be accessed between tests due to this design.

Categories