How and when to cleanup using Mockito Annotations with jUnit - java

I'm currently having some memory problems with some unit tests in a fairly large project of mine. Throughout my hair pulling and research today, I have come to realize that it appears to be related to objects not always being cleaned up as fast as I think they should be cleaned up. I started researching "cleanup mockito" and "cleanup junit" and came across a few blogs and forum posts about how to use #Before and #After (as well as their *Class versions) to do intense things that you don't want being done with every unit test. This got me to thinking about Mockito's #Mock and #InjectMocks annotations.
Can someone please describe to me in detail how the class variables below are being handled in memory during a maven build? Will the objects be created before, during, or after unit tests? Are the objects immediately destroyed after the last unit tests completes? Should I be using #After to set all the class variables to null?
Thanks many times over. Here's a sample of a test case I may use:
#RunWith(MockitoJUnitRunner.class)
public class thisCustomTest {
#Mock
MyCustomSpringBean myCustomerSpringBean;
#InjectMocks
MyBeanToTest myBeanToTest;
#Before
public void config() {
MockitoAnnotations.initMocks(this);
}
#Test
public void someTest() {
//code here
}
}
Just to do a quick wrap-up / summary at the end, my main question is whether or not I should be utilizing something like #After to clean up class variables, or should I simply leave those for Java's normal scope garbage collection...
My idea of cleanup:
#After
public void cleanup() {
mockedClassVariable = null;
injectedVariable = null;
}

JUnit creates a new instance of your unit test class before running each test method. Once the instance is created, its #Before annotated method(s) is (are) executed. Then the test method is executed. Then, whatever happened in the test method (success, failure or error), the #After annotated method(s) is (are) run.
So, in this particular case, MockitoAnnotations.initMocks(this) is executed before each test method, which creates a new mock each time, a new MyBeanToTest each time, and injects the mock into the bean to test.
Those beans will be eligible for GC, along with the test instance which references them, after the test method execution. Setting them to null in the cleanup method doesn't serve any purpose.

Related

Mockito throws UnnecessaryStubbingException for stub defined in generic #BeforeEach setup method

I have a unit test class where my unit under test is dependent on another class. The dependency is mocked using Mockito and then setup with a generic stub that's run before every unit test, using JUnit's #BeforeEach annotation. See the below pseudo-code.
#ExtendWith(MockitoExtension.class)
public class FooFactoryTest {
#Mock
private BarDependency barDependency;
#InjectMocks
private FooFactory unitUnderTest;
#BeforeEach
public void setup() {
when(barDependency.leftBar(any())).thenReturn(new Bar());
when(barDependency.rightBar(any())).thenReturn(new Bar());
}
... many tests ...
This setup works perfectly for 9 of my 10 unit tests. Unfortunately one of my tests is failing with the following error:
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
Unnecessary stubbings detected.
Clean & maintainable test code requires zero unnecessary code.
Following stubbings are unnecessary (click to navigate to relevant line of code):
1. -> at nl.devillers.mockito.FooFactoryTest.setup(FooFactoryTest.java:69)
Please remove unnecessary stubbings or use 'lenient' strictness. More info: javadoc for UnnecessaryStubbingException class.
Now, I understand the error and why it's thrown, because in that specific test my unit under test short-circuits early and doesn't hit all the stubs that have been setup. I'm aware there's a lenient option in Mockito, but that'll disable the check for the entire class/project.
My question is: how do I disable this strictness for one specific unit test?
Again: I do not want to disable the strictness at the class or project level, since I think it's valuable check. I also do not want to move my setup code to the tests that do need the stubs, because then I have to duplicate the setup code nine times. In this case I just want to disable or skip the check for this specific test.
You can avoid this check at the test-level by resetting the mock with the stub that's not being called. This is a bit of a work around, but it'll allow you to pass your test without having to make the mock lenient for your entire test class or removing the mock entirely from your setup method.
To reset your barDependency mock, add the following line of code to the end of your test that is failing with a UnnecessaryStubbingException.
Mockito.reset(barDependency);
If none of the stubs on barDependency are being used, you can also place this line at the beginning of your test with your other arrangements, which is a little cleaner. Or alternately, put it at the top of your test method and then setup the stubs you do need. This essentially overrides whatever is being setup in your generic setup method.
You can also use lenient in the code of your #BeforeEach, like this:
#BeforeEach
public void setup() {
lenient().when(barDependency.leftBar(any())).thenReturn(new Bar());
lenient().when(barDependency.rightBar(any())).thenReturn(new Bar());
}
This should not be necessary, based on this doc in the UnnecessaryStubbingException:
Mockito JUnit Runner triggers UnnecessaryStubbingException only when none of the test methods use the stubbings. This means that it is ok to put default stubbing in a 'setup' method or in test class constructor. That default stubbing needs to be used at least once by one of the test methods.

JUnit android test classinheritance

I have simple Android application with some espresso tests.
I want to write some base class so all of my test classes will inherit its #beforeClass and #afterClass methods, but the problem is when I do it like code example below, JUnit doesn't see any tests at al. I got Empty test suite. message. What's the problem?
Code example:
public class RealmTest {
protected static Realm realm;
#BeforeClass
public static void beforeClass() {
realm = Realm.getDefaultInstance();
realm.setAutoRefresh(true);
}
#AfterClass
public static void afterClass() {
realm.close();
}
}
#RunWith(AndroidJUnit4.class)
public class MainActivityTest extends RealmTest {
#Rule
public IntentsTestRule<MainActivity> activityTestRule = new IntentsTestRule<>(MainActivity.class);
#Test
public void startedFine() {
assertNotNull(realm);
onView(withId(R.id.button)).perform(click());
intended(hasComponent(new ComponentName(getTargetContext(), EducationActivity.class)));
}
}
If I'll run all tests, tests from MainActivityTest won't run.
Thanks for your help, pls say if some additional info is needed.
Guessing: the JUnit environment is not looking for static methods. So maybe you simply drop that keyword from your base methods (guess you could keep your Realm static nonetheless; I assume you really only want one of those).
But then, another suggestion: don't use inheritance for test cases.
The point that makes test cases valuable to you is: they should quickly allow you to find and fix bugs in your production code.
But when your "setup" is hidden from your testcases - because things are not only happening in some #Before method ... but in a #Before method somewhere, in some different class ... well, that can seriously increase the time you will need to understand a failing testcase. Because: instead of just studying your test case, you find yourself digging around within test code in order to understand what exactly is happening besides the code in that failing test method itself!
Thus: be really careful to balancing "code duplication" versus "test case is easy to understand" aspects!

How do you clear objects between JUnit/Maven tests?

I'm testing different parts of a miniature search engine, and some of the JUnit tests are leaving entries in the index that interfere with other tests. Is there a convention in JUnit/Maven for clearing objects between tests?
There are 2 particular annotations that can help you with this, and are intended to be used in cases such as yours:
#After defines that a certain method must be executed after every #Test, while #AfterClass is the method to execute once the entire test class has been executed. Think of the latter as a last cleanup method to purge any structures or records you've been using and sharing between tests so far.
Here is an example:
#After
public void cleanIndex() {
index.clear(); //Assuming you have a collection
}
#AfterClass
public void finalCleanup() {
//Clean both the index and, for example, a database record.
}
Note: They have their counterparts (#Before and #BeforeClass) that to exactly the opposite by invoking the related methods before a #Test method and before starting to execute the #Tests defined on that class. This ones are the setUp used in previous versions of JUnit.
If you can't use annotations, the alternative is to use the good old tearDown method:
public void tearDown() {
index.clear(); //Assuming you have a collection.
}
This is provided by the JUnit framework and behaves like a method annotated with #After.
You should make use of the #Before annotation to guarantee that each test is running from a clean state. Please see: Test Fixtures.
Inside of your junit testing class, you can override the methods setup and teardown. setup will run before every one of your tests while teardown will run after every single junit test that you have.
ex:
public class JunitTest1 {
private Collection collection;
//Will initialize the collection for every test you run
#Before
public void setUp() {
collection = new ArrayList();
System.out.println("#Before - setUp");
}
//Will clean up the collection for every test you run
#After
public void tearDown() {
collection.clear();
System.out.println("#After - tearDown");
}
//Your tests go here
}
This is useful for clearing out data inbetween tests, but also allows you to not have to reinitialize your fields inside of every single test.

How can I make JUnit 4.8 run code after a failed test, but before any #After methods?

I'm driving a suite of Selenium tests (actually WebDriver-backed Selenium) using JUnit 4.8.2. I'd like the tests to automatically take a screenshot of the browser as soon as the test fails an assertion. All the tests inherit from SeleniumBaseTestCase, and the majority then further inherit from from SeleniumBastTestCaseWithCompany (which uses #Before and #After methods to create and then clean up common test data via Selenium).
I've tried adding a subclass of TestWatchman as a #Rule in SeleniumBaseTestCase, overriding TestWatchman's failed method to take the screenshot. The trouble is that the #After methods cleaning up the test data are being run before TestWatchman's failed method is called, so the screenshots are all of the final step of the clean-up, not the test that failed.
Looking into it a little, it seems that TestWatchman's apply method just calls the passed Statement's evaluate method (the only exposed method), which calls the #After methods, leaving TestWatchman (or any other Rule) no chance to insert any code between the execution of the test and of the #After methods, as far as I can tell.
I've also seen approaches that create a custom Runner to alter the Statements created so that methods annotated with the custom #AfterFailure are run before #After methods (so the screenshot can be taken in such an #AfterFailure method), but this relies on overriding BlockJUnit4ClassRunner's withAfters method, which is deprecated and due to become private, according to the documentation, which suggests using Rules instead.
I've found another answer on SO about the #Rule lifecycle that makes it sound like this simply might not be possible in JUnit 4.8, but may be possible in JUnit 4.10. If that's correct then fair enough, I'd just like confirmation of that first.
Any thoughts on an elegant and future-proof way in which I can achieve what I want would be much appreciated!
You are right in your analysis, #Befores and #Afters are added to the list of Statements before any Rules. The #Before gets executed after the #Rule and the #After gets executed before the #Rule. How you fix this depends on how flexible you can be with SeleniumBaseTestCaseWithCompany.
The easiest way would be to remove your #Before/#After methods and replace them with an ExternalResource. This could look something like:
public class BeforeAfterTest {
#Rule public TestRule rule = new ExternalResource() {
protected void before() throws Throwable { System.out.println("externalResource before"); }
protected void after() { System.out.println("externalResource after"); }
};
#Test public void testHere() { System.out.println("testHere"); }
}
this gives:
externalResource before
testHere
externalResource after
This field can be put into your base class, so it gets inherited/overridden. Your problem with ordering between #After and your rules then goes away, because you can order your rules how you like, using #RuleChain (in 4.10, not 4.8).
If you can't change SeleniumBaseTestCaseWithCompany, then you can extend BlockJUnit4ClassRunner, but don't override withAfters, but override BlockJUnit4ClassRunner#methodBlock(). You can then call super.methodBlock, and reorder the Statements as necessary[*].
[*]You could just copy the code, and reorder the lines, but withRules is private and therefore not callable from a subclass.

mockito : how to unmock a method?

I have a JUnit class with different methods to perform different tests.
I use Mockito to create a spy on real instance, and then override some method which is not relevant to the actual test I perform.
Is there a way, just for the sake of cleaning up after me in case some other tests that run after my tests also use the same instances and might execute a mocked method they didn't ask to mock, to un-mock a method?
say I have a spy object called 'wareHouseSpy'
say I overriden the method isSomethingMissing :
doReturn(false).when(wareHouseSpy).isSomethingMissing()
What will be the right way to un-override, and bring things back to normal on the spy i.e make the next invokation of isSomethingMissing to run the real method?
something like
doReturn(Mockito.RETURN_REAL_METHOD).when(wareHouseSpy).isSomethingSpy()
or maybe
Mockito.unmock(wareHouseSpy)
Who knows? I couldn't find nothing in that area
Thanks!
Assaf
I think
Mockito.reset(wareHouseSpy)
would do it.
Let's say most of your tests use the stubbed response. Then you would have a setUp() method that looks like this:
#Before
public void setUp() {
wareHouseSpy = spy(realWarehouse);
doReturn(false).when(wareHouseSpy).isSomethingMissing();
}
Now let's say you want to undo the stubbed response and use the real implementation in one test:
#Test
public void isSomethingMissing_useRealImplementation() {
// Setup
when(wareHouseSpy.isSomethingMissing()).thenCallRealMethod();
// Test - Uses real implementation
boolean result = wareHouseSpy.isSomethingMissing();
}
It depends whether you are testing with TestNG or JUnit.
JUnit creates a new instance of itself for each test method. You basically don't have to worry about reseting mocks.
With TestNG, you have to reset the mock(s) with Mockito.reset(mockA, mockB, ...) in either an #BeforeMethod or an #AfterMethod
The "normal" way is to re-instantiate things in your "setUp" method. However, if you have a real object that is expensive to construct for some reason, you could do something like this:
public class MyTests {
private static MyBigWarehouse realWarehouse = new MyBigWarehouse();
private MyBigWarehouse warehouseSpy;
#Before
public void setUp() {
warehouseSpy = spy(realWarehouse); // same real object - brand new spy!
doReturn(false).when(wareHouseSpy).isSomethingMissing();
}
#Test
...
#Test
...
#Test
...
}
Maybe I am not following but when you have a real object real:
Object mySpy = spy(real);
Then to "unspy" mySpy... just use real.
As per the documentation, we have
reset(mock);
//at this point the mock forgot any interactions & stubbing
The documentation specifies further
Normally, you don't need to reset your mocks, just create new mocks
for each test method. Instead of #reset() please consider writing
simple, small and focused test methods over lengthy, over-specified
tests.
Here's an example from their github repo which tests this behavior and uses it:
#Test
public void shouldRemoveAllInteractions() throws Exception {
mock.simpleMethod(1);
reset(mock);
verifyZeroInteractions(mock);
}
reference : ResetTest.java
Addressing this piece specifically:
Is there a way, just for the sake of cleaning up after me in case some other tests that run after my tests also use the same instances and might execute a mocked method they didn't ask to mock, to un-mock a method?
If you are using JUnit, the cleanest way to do this is to use #Before and #After (other frameworks have equivalents) and recreate the instance and the spy so that no test depends on or is impacted by whatever you have done on any other test. Then you can do the test-specific configuration of the spy/mock inside of each test. If for some reason you don't want to recreate the object, you can recreate the spy. Either way, everyone starts with a fresh spy each time.

Categories

Resources