Does the #Before annotation in JUnit call a method automatically? - java

I have the following test in JUnit:
#Test
public void getLargestCustId_should_return_five(){
Assert.assertEquals(5, project.getLargestCustId());
}
However, it throws a NullPointerException, because the project-object is not initialized. This is despite the fact that I have created an init-method with the #Before annotation:
#Before
public void init(){
project = new Project();
personOne = new Person(-3);
personTwo = new Person(1);
personThree = new Person(5);
project.addPerson(personOne);
project.addPerson(personTwo);
project.addPerson(personThree);
}
When I move this whole code into the getLargestCustId_should_return_five() it works and the Project-class is initialized correctly.
I thought the #Before-annotation made sure that the init() method will be automatically called? Without me having to call this.init() inside the other methods. Is this correct? Or do I have to explicitly call the method when the class is run?

From JavaDoc
When writing tests, it is common to find that several tests need similar
objects created before they can run. Annotating a public void method
with #Before causes that method to be run before the #Test method.
The #Before methods of superclasses will be run before those of the current class,
unless they are overridden in the current class. No other ordering is defined.

Related

How is it possible to initialize the Junit5 Mocks annotated with #Mock before each test using MockitoExtension?

I would like to create some Junit test using the annotation #Mock and MockitoExtension.
Something like this:
#ExtendWith(MockitoExtension.class)
public class Test {
#Mock
MyObject mock;
#Test
public void test1() {
..
}
#Test
public void test2() {
..
}
How can I tell to MockitoExtension that it has to create the mock before each test execution to isolate them?
I would like to avoid that the first executed test defining a behavior for the mock with when(mock.doSomething()).then(returnSomething()) will not influence the other tests by resetting the mock)
It's not just Mockito that is reinitialized, it's standard JUnit behavior. A new instance of your Test class is created for each method. So this creates isolation between each test for anything you set up as instance members, including Mockito instances.
You can imagine your test is run like this:
Test instance1 = new Test();
instance1.test1();
Test instance2 = new Test();
instance2.test2();
You can set behavior for each instance using #BeforeEach:
#BeforeEach
void setUp() {
// this runs for every test method on a brand new scope
}
notice how it is an instance method.
If you do want "global" behavior, you use static methods and variables instead. The corresponding annotations are #BeforeAll/#AfterAll which must be applied to static methods and runs once each for the whole class.

Testing lazy initialization by j.u.f.Supplier with Mockito

I have a class Sut with lazy initialization implemented using java.util.function.Supplier. In fact it's more complicated that the code below, but this is the simplest form that Mockito cannot test. The test below throws an error Wanted but not invoked ... However, there were other interactions with this mock. Why doesn't Mockito count the invocation of create? The code flow actually enters create(); I checked that with debugger.
import java.util.function.Supplier;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
public class TestTimes {
#Test
public void testCreateOnlyOnce() {
Sut sut = spy(new Sut());
sut.getData();
sut.getData();
sut.getData();
verify(sut, times(1)).create();
}
private static class Sut {
Supplier<Object> data = this::create;
void getData() {
data.get();
}
Object create() {
return new Object();
}
}
}
First of all, thanks for the well written question.
I have tested your code myself and seen the error you mentioned. Although, I have changed your code a little bit while debugging... Take a look:
#Test
public void testCreateOnlyOnce() {
Sut sut = spy(new Sut());
sut.getData();
sut.getData();
sut.getData();
verify(sut, times(1)).create();
}
private static class Sut {
private Supplier<Object> data;
// Added de data object initialization on the constructor to help debugging.
public Sut() {
this.data = this::create;
}
void getData() {
data.get();
}
Object create() {
return new Object();
}
}
What I found out while debugging:
The Sut class constructor is being called correctly inside the spy(new Sut()) clause, but the create() method is not being called there.
Every time sut.getData() is called, the create() method is also called. What made me conclude, finally that:
On the constructor, all that this::create did was telling java that, whenever it needs to retrieve the Object from the supplier, that Object will be retrieved from the create() method. And, the create() method being called by the supplier is from a class instance different from what Mockito is spying.
That explains why you cannot track it with verify.
EDIT: From my research, that is actually the desired behavior of the Supplier. It just creates an interface that has a get() method that calls whatever noArgs method you declared on the method reference. Take a look at this on "Instantiate Supplier Using Method Reference".
I want to add a little to Gabriel Pimentas excellent answer. The reason why this works as it does is that mockito creates shallow copies of the spy new Sut() and your Supplier refers to the compiled lambda method inside the original Sut instance and not the spy instance.
See also this question and the mockito documentation.
When you debug your code, you can see how this works:
Sut sut = spy(new Sut()); is now a mocked/spied subclass of Sut as the instance TestTimes$Sut$MockitoMock$1381634547#5b202a3a. Now, all fields from the original new Sut() are shallow-copied, including the Supplier<Object> data. Looking at this field inside the spy, we can see that it is an instance of TestTimes$Sut$$Lambda$1/510109769#1ecee32c, i.e. pointing to a lambda inside the original Sut. When we set a breakpoint inside the create method, we can further observe that this points to TestTimes$Sut#232a7d73, i.e. the original Sut and not the spied instance.
EDIT: Even though this MCVE probably does not resemble your actual code, the following solutions come to mind:
Inject the Supplier into your Sut (either during construction or as a parameter to getData.
Create the supplier lazily within your getData method (so that it points to the mockito-instance)
Don't use a Supplier but just call create directly if the Supplier is not passed from the outside

In a JUnit test is there a rule to set the subject of the test

I've been writing a lot of JUnit tests lately and see this same boilerplate pattern.
public class MathOpTest {
private MathOp a;
#Before
public void setUp(){
a = new MathOp();
}
...
}
Is there an annotation to set this up for me as I always need to write a setUp method and it usually only has the single class I'm testing.
Something like:
public class MathOpTest {
#TestSubject
private MathOp a;
...
}
You can assign the fields when they are declared:
public class MathOpTest {
private final MathOp mathOp = new MathOp();
...
}
This is simple and straight-forward, so I recommend that you assign fields in your test class at declaration time whenever possible (certainly in the case you gave).
If you want to understand a bit more, read on.
JUnit will create a unique instance of your test class for each test method, so even if your test modifies internal state of MathOp, using fields this way is safe as long as your tests don't modify global state.
For JUnit4-style tests (i.e. tests that do not extend junit.framework.TestCase) JUnit will create the test class just before the test method is run, and make it eligible for garbage collection after the test method completes.
Use #Before methods for more complex initialization.
Usually I use #Before when:
Initialization of the field is complex
Initialization of the field requires calling code that is declared to throw a checked exception
You need to do initialization after a #Rule has been applied (for instance, injecting a mock into a constructor)
Usually you would create the object under test in the test method when the class needs to be constructed different ways for different use cases.
Examples
Here is an example of using #Before and initMocks():
public class MathOpTest {
#Mock private Calculator mockCalculator;
#Mock private Supplier<Double> mockPreviousResultSupplier;
private MathOp mathOp;
#Before
public void createMathOp() {
MockitoAnnotations.initMocks(this);
mathOp = new MathOp(
mockCalculator, mockPreviousResultSupplier);
}
...
}
Here's an example of a #Before method that uses the result of a #Rule:
public class MyWriterTest {
#Rule public final TemporaryFolder folder = new TemporaryFolder();
private File output;
private MyWriter writer;
#Before
public void createMyWriter() {
output = folder.newFile();
writer = new MyWriter(output);
}
...
}
Aside: I personally wouldn't recommend using #InjectMocks to create the class you are testing. It's too much magic for my taste. Having an explicit constructor is cleaner and simpler, and I like my tests to be clear and simple :-)
Nothing like this directly exists in vanilla JUnit to my recollection. Most people elect to either initialize their test subject in a #Before statement, or inside of their tests. In its defense, it makes it clear what is being established before the tests are run, and it always resets the state of your test object.
If you're using Mockito, you actually do have the benefits of declaring a class and annotating it with #InjectMocks to both instantiate the class and inject whatever #Mock classes you had prior.

Mockito NotaMockException

I am facing an issue with Mockito junit testing. I am new to it and am a bit confused with the problem I am facing. Any help on this would be appreciated.
class Activity{
public void firstMethod(){
String str = secondMethod();
}
public String secondMethod(){
String str = null;
/* some Code */
return str;
}
}
Getting exception :
*org.mockito.exceptions.misusing.NotAMockException:
Argument passed to when() is not a mock!*
in the below code
class ActivityTest(){
Activity act;
#Before
public void setup(){
act = new Activity();
}
#Test
public void testFirstMethod(){
Mockito.doReturn(Mockito.anyString()).when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
I am aware that activity is not a mock but I am not sure for a way around this as secondMethod() is a method in the same class. I need to write rule for secondMethod() as I have already done its Unit Testing. The definition of secondMethod() consists has external dependencies. Should I be mocking the external dependencies present in secondMethod() and writing rules for them rather than rule for secondMethod()?
I found this post:
Mockito Spy'ing on the object being unit tested
However separating the secondMethod() into a different class does not make sense. My method is related to this class. Creating a different class for testing does not seem right to me. Even mocking the actual class using spy() is not the most correct way as already explained in the post.
I don't think I should be creating a mock of the Activity class as that is the class I am testing. I would really appreciate help and insights into this.
As you noted, act is not a mock, and therefore you cannot record behavior on it. You could use Mockito.spy to, well, spy (or partially mock) the act object so that you only record the behavior of secondMethod and execute the actual code for firstMethod.
Note, however, that matchers can't be used in doReturn calls regardles of how you're mocking or spying your object. A return value must be a concrete object.
class ActivityTest() {
Activity act;
#Before
public void setup(){
act = Mockito.spy(new Activity()); // Here!
}
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
A slightly more elegant syntax allows you to use annotations instead of explicitly calling Mockito.spy, but it's a matter of taste really:
#RunWith(MockitoJUnitRunner.class)
class ActivityTest() {
#Spy
Activity act = new Activity();
#Test
public void testFirstMethod(){
Mockito.doReturn("someString").when(act).secondMethod();
act.firstMethod();
verify(act).secondMethod();
}
}
There is no reason to mock anything in this example. Since there are no dependencies and both methods are public, you can test them directly.
public class ActivityTest() {
private Activity act = new Activity();
#Test
public void testSecondMethod(){
assertEquals("expected-value", act.secondMethod());
}
#Test
public void testFirstMethod() {
act.firstMethod();
// success if no exception occurs
}
}
Since firstMethod does not have any detectable effect on the Act instance, nor on any dependency (since there are none) you can simply call the method and be satisfied if no exception is thrown. One could also reason that such a method should not be tested at all.
I assume the example given is a simplification of a class where calling firstMethod actually does have side effects, who knows...
Here are some hints:
Mock the Activity.
Tweak the behavior of secondMethod with when / then / doReturn
Use doCallRealMethod when firstMethod is invoked.
Hope it helps.

JUnit: #Before only for some test methods?

I have some common set up code that I've factored out to a method marked with #Before. However, it is not necessary for all this code to run for every single test. Is there a way to mark it so the #Before method only runs before certain tests?
Just move out the tests that don't need the setup code into a separate test class. If you have some other code common to the tests that would be helpful to keep, move that out into a helper class.
#Nested + #BeforeEach
Totally agree with the point of moving the related code to an inner class. So here what I have done.
Create an inner class inside your test class
Annotate the inner class with #Nested
Move all the test methods you want to use in the inner class
Write the init code inside the inner class and annotate it with #BeforeEach
Here is the code:
class Testing {
#Test
public void testextmethod1() {
System.out.println("test ext method 1");
}
#Nested
class TestNest{
#BeforeEach
public void init() {
System.out.println("Init");
}
#Test
public void testmethod1() {
System.out.println("This is method 1");
}
#Test
public void testmethod2() {
System.out.println("This is method 2");
}
#Test
public void testmethod3() {
System.out.println("This is method 3");
}
}
#Test
public void testextmethod2() {
System.out.println("test ext method 2");
}
}
Here is the output
test ext method 1
test ext method 2
Init
This is method 1
Init
This is method 2
Init
This is method 3
Note: I am not sure if this is supported in Junit4. I am doing this in JUnit5
It is possible to achieve also via Assume from JUnit. And then you can check the method name for which you want to process #Before.
public class MyTest {
#Rule
public TestName testName = new TestName();
#Before
public void setUp() {
assumeTrue(testName.getMethodName().equals("myMethodName"));
// setup follows
}
}
Check the topic for more insights about #Rule.
Now that it's 2023, I'd recommend sticking with JUnit 5.x
I'd also say that this is probably a micro-optimization. I would not go to the effort until I measured my test time and saw that running the code when it wasn't necessary added a significant amount of time.
Not sure about #Before, but I recently came up with a strategy for #After block to run selectively. The implementation was straight forward. I have some flags set to default values as part of the test class. They are reset to default values in #Before class. In the class I need to do things specific to a flag, I set those flags & in #After I check for flag values to do the respective jobs.
JUnit 4.12 provide Enclosed Runner like
#RunWith(Enclosed.class)
public class GlobalTest{
#RunWith(MockitoJUnitRunner.class)
public class InnerTest{
}
}

Categories

Resources