Does Junit reinitialize the class with each test method invocation? - java

When i run the below code, both test cases come true:
import static junit.framework.Assert.assertEquals;
import org.junit.Test;
public class MyTest{
private int count;
#Before
public void before(){
count=1;
}
#Test
public void test1(){
count++;
assertEquals(2, count);
}
#Test
public void test2(){
count++;
assertEquals(2, count);
}
}
EXPECTED BEHAVIOUR
test1 - success
test2 - fail(as expected that count will become 3)
ACTUAL BEHAVIOUR
test1 - success
test2 - success
Why junit is reinitializing class/variable with each test method invocation.
It is a bug in junit or is provided intentionally.

It is because of test isolation.
No test should depend on another.

New Instance of MyTest for each test method
For each test method a new instance of MyTest will be created this is the behavior of Junit.
So in your case for both methods the variable count will have value 1, and thus the value of count++ will be 2 for both the test methods and hence the test cases pass.
public class MyTest{
public MyTest(){
// called n times
System.out.println("Constructor called for MyTest");
}
#Before //called n times
public void setUp(){
System.out.println("Before called for MyTest");
}
//n test methods
}
If you execute the code above with 2 test methods:
Output will be:
Constructor called for MyTest
Before called for MyTest
//test execution
Constructor called for MyTest
Before called for MyTest
Edit:
Isolation from the F.I.R.S.T principle of testing
Test frameworks help you in doing the right thing, a very important property of unit tests is isolation.
By creating a new instance every test method, the dirty SUT is thrown away. So that we have a fresh state for every test.
Read about F.I.R.S.T principle of testing.

Look at the documentation of org.junit.runner.Runner:
The default runner implementation guarantees that the instances of the
test case class will be constructed immediately before running the
test and that the runner will retain no reference to the test case
instances, generally making them available for garbage collection.
Unit tests should be independant otherwise it becomes unmaintable. Note that the order of executed methods is not guaranteed (unless you use the annotation #FixMethodOrder).

Answer for JUnit 5
In JUnit5, this behavior is controlled using the #TestInstance annotation. The annotation can take as value one of two lifecycle qualifiers:
#TestInstance(Lifecycle.PER_CLASS): The test class will be initialized once for all the methods in the class.
#TestInstance(Lifecycle.PER_METHOD): The test class will be reinitialized before each test method (the behavior described in other answers).
If a test class is not annotated with #TestInstance, the default behavior is PER_METHOD.
For more details, see Test Instance Lifecycle in the JUnit5 User Guide.

If you want to use test class's member variable for all tests , without it being reinitialised to null, then make it static.

Don't initialize test class state in a constructor unless it is immutable.
JUnit does not instantiate your test class for every #Test. In fact it only runs methods marked #Before before each one, and will run #BeforeClass methods once before all of the tests in the class.
However you are not guaranteed that the test runner will actually use just one instance of your test class to run the tests. It is free to use many -- consider running a bunch of tests in parallel, even on different machines.
While there are JUnit runner settings to control this in general, it's much better to simply follow the JUnit design and initialize test state in a method marked #Before only.

Related

Write a Mock method applicable only for specific tests in a test class

I have a test class in which I have around 10 unit test cases. In this, I have a mock method created which is useful in just 2 of the 10 test cases.
public static class MockCreateStudent extends Mockup<CreateStudentDAO>{
#Mock
public boolean isFeesPaid(long studentID){
return true;
}
}
So technically I want the isFeesPaid() method to be executed as-is for 8 test cases and mocked for 2 of the test cases.
Is there any way this can be achieved?
Use a spy in that case instead of a mock. For most of the cases, it will invoke the real implementation of the collaborator and for those 2 cases, you use the given().willReturn() stubbing in the //Given section just before you invoke the SUT.
Here is more info on the spy annotation which I would recommend you use: link

Mocking constructor using powermock on the class which needs to be tested

I am able to mock a constructor call using powermock from inside a class which I want to test. This works when I add the class I want to test in #PrepareForTest. But once I add my class there, even when the test cases pass, the coverage is being shown as 0 in the coverage plugin.
When I remove my class from #PrepareForTest, of course, coverage starts showing up for other test cases but the test case in which I have to mock constructor call fails. Not sure what to do about this.
Class A
{
MyObject o;
A(){
//some other code
o = new MyObject();
//some other code
}
public void process(){
//some code
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(A.class)
Class TestA{
#Test
public void test1()
{
MyObject mocked = Mockito.mock(MyObject.class);
PowerMockito.whenNew(MyObject.class).withNoArguments().thenReturn(mocked);
A a = new A();
a.process();
//Assert as per test case
}
}
In coverage tool, coverage shows as 0 however, unit test passes and I checked in debug mode that it was covering all the statements of class A.
In coverage tool, coverage shows as 0 however, unit test passes and I checked in debug mode that it was covering all the statements of class A.
Coverage tools rely on manipulating the executed byte code.
So does PowerMock, when you mock static/new.
This can quickly lead to all sorts of problems. For JaCoCo, there seems to be a solution around offline instrumentation. Where, I also remember: some other person asked about that some time back, and in the end gave up, because he couldn't get "offline instrumentation" to work either.
For any other framework, I have to repeat old advice: consider to invest your time to learn how to write easy-to-test code. Because if you would do that, you would not need to use PowerMock(ito) in order to test it.
Your code is hard-to-test because of that new() statement in the constructor. Simply don't do that. Either use dependency injection via #InjectMocks, or have a test-only constructor that takes the required object.
Long story sort: when you write your own, new code, and you think you need PowerMock to test it, then you are doing something wrong.
I think you can do without Powermock here. If you Spy on class A and mock the getter you should end up with the same result and most likely have your coverage correct:
#Test
public void test1(){
MyObject mocked = Mockito.mock(MyObject.class);
A spyA = Mockito.spy(new A());
doReturn(mocked).when(spyA).getMyObject();
...
}

Race condition when running junit test in parallel

I am wondering would it have some race condition if I run my tests in parallel and the two tests (below) share an instance variable? So my test class runs with SpringJunit4ClassRunner, and I have 2 tests method a() and b(), the variable state will be modified or reassigned from each test, and the doSomethingWithState() would use the variable state and pass it to the testing method. I know with maven-surefire-plugin you can run it at the method level that both a() and b() will get assigned to a thread and run it in parallel.
#RunWith(SpringJUnit4ClassRunner.class)
public class TestA {
private Object state;
#Test
public void a() {
stateObjectA();
doSomethingWithState();
assertion();
}
#Test
public void b() {
stateObjectB();
doSomethingWithState();
assertion();
}
private void stateObjectA() {
// do some mocking and setup state
}
private void stateObjectB() {
// do some mocking and setup state
}
private void doSomethingWithState() {
// use the state object and feed into the testing method
}
}
I guess the only reasonable answer is: depends ... on your exact context and code base.
The essence if race conditions is: you have more than one thread manipulating ("writing") to shared data. Your lengthy question boils down to exactly such a setup. So there is high potential for race conditions in the setup that you described above.
And then: it doesn't make any difference if you are talking about methods in production code or methods called by some testing framework. Because race conditions do not care about that. They only "care" about more than one thread writing to shared data.
That is all that matters here!
You must take into account two things:
If you require to use instance variables, you instantiate them before loading (Junit4 provides #Before, #After annotations, and #BeforeClass and #AfterClass for static variables).
Junit doesn't guarantee you that it will run the test cases in the same order every time, so each test must be coded isolated from the rest.
Another obvious point is that you must not think tests based on the results of the others. Take this into account when mocking stuff for integration tests, perhaps tests will begin to fail randomly and you won't know why.

JUnit 4: Test case returns an object used in other tests in the test suite

I have created several tests cases for my application, all these are chained in a single test suite class.
However, i would like to pass an object created in the first test to the others.
To be clearer, the first test tests a class that creates a complex object with data coming from my database. I would like the others to test the methods of the object itself.
Here is how i define my test suite class:
package tests.testSuites;
import tests.Test1;
import tests.Test2;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
#RunWith(Suite.class)
#SuiteClasses({
Test1.class
Test2.class
})
public class DataTestSuite {
}
But I would like to have something like this somewhere:
MyObject obj=Test1.testcreation();
Test2.testMethod(obj);
How can I combine a regular JUnit testSuite class definition with the need to pass the created object to my other test?
EDIT
For information, the test suite is launched in a test runner class. This class helps formatting the results and creates a custom log file.
This is how it calls the test suite:
public class MetExploreTestRunner {
public static void main(String[] args) {
Result result=JUnitCore.runClasses(DataTestSuite.class);
if(result.wasSuccessful()){
System.out.println("All tests succesful ");
}else{
for(Failure failure:result.getFailures()){
System.out.println(failure.toString());
}
}
}
}
Do not do that. Each test should be independent of the others. You can then run tests singly, to debug them, and each test is easier to understand. Also, JUnit runs tests in an arbitrary order; you can not guarantee that the object will be created before it is used.
If several tests use a similar object, consider extracting the code for creating it into a shared private method of the test class. If many tests use the object, consider making it a test fixture set up by a #before method.
After a lot of searching on the internet, I found what I was looking for.
The library JExample allows you to create dependencies between different tests and to pass arguments between them which is what I needed. http://scg.unibe.ch/research/jexample
I really recommend it.
Thank you all for your answers
You can use #Rule instead of reuse some data from one test to the others. You can see an example of use here: https://github.com/junit-team/junit/wiki/Rules
That rule can create that big object and then you can use it in every test you want.
I don't recommend you to create any dependency between tests because things could change in the future and you'd have to change many things in your other tests.
If you really want to do what you said, there is an annotation #dependsOn that would be usefull for you
It seems that you are doing integration testing instead of unit tests.
What you can do is to:
Create mock class that connects to your database and creates this complex object
Write a new class that will run all your tests and will create an instance of your mock class (this might be helpfull http://www.tutorialspoint.com/junit/junit_suite_test.htm )
Create methods with #BeforeClass annotation that will get this object.
Run your tests.
For my point of view it is not very practical, and not unit test at all. Unit tests should be independent, and do not rely on other tests.
Why not factor out the creation of MyObject to a utility class?
public class Test2{
...
#Test
public void testMethod(){
MyObject obj = TestUtil.createMyObject();
//do test here
}
}
You can then call the TestUtil.createMyObject() from any test. Also if creating MyObject is expensive, you can lazily create it and cache the result or use any of the other patterns useful for factory methods.

How JUnit manages running #BeforeClass only once which is defined inside the test class

I very much understand what #BeforeClass is. It is executed once before JUnit test run is started & #Before method is executed before every test case.
My question is regarding a very old post by a very senior stackoverflow user (Péter Török
68.8k) Please refer [stackoverflow question]
[1]: JUnit: using constructor instead of #Before which was posted about 2 yrs ago but on JUnit4. so I think it is still valid and true.
Here he mentions
#Before is equivalent to constructor of test class
and
JUnit creates a new instance of the test class for each #Test,
So how does JUnit manage running #BeforeClass only once which is defined inside the test class?
Methods annotated with #BeforeClass must be static. JUnit doesn't need any instance of the test class to call it.
Well, jUnit could run the method annotated with #BeforeClass at time of class loading, that is like you would implement on your own with a static initializer.
You get also the hint that jUnit is doing something like this by the fact that #BeforeClass and #AfterClass annotated methods must be static.
That's because #BeforeClass has to be a static method. Once it is static, JUnit knows how to run it once.
Sometimes several tests need to share computationally expensive setup (like logging into a database). While this can compromise the independence of tests, sometimes it is a necessary optimization. Annotating a public static void no-arg method with #BeforeClass causes it to be run once before any of the test methods in the class. The #BeforeClass methods of superclasses will be run before those the current class. Static methods are not belongs to instances of the class. Those are properties of the class.

Categories