#Before and #After exclusion - java

I'm writing some tests for my DAO, and because a lot of the tests use a test object that is being saved to my database I've created a setup() and teardown() method with the annotations #Before and #After respectively to avoid redundant code, but one of the tests, actually one that doesn't really need the test object, calls a method in the DAO that contains the call getCurrentSession().clear() (it's a method that uses ScrollableResults to get data from the db in batches, and to avoid the memory to fill up it calls flush() and clear() every 50 rows). This creates a problem, because the clear() actually removes the test object that is created in setup() from the session, so when teardown() is called I get an error:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [nl.ru.cmbi.pdbeter.core.model.domain.PDBEntry#395]
Is there a way to tell JUnit to not use the setup() and teardown() on this test, or is it better to put all the tests that don't actually need the setup() and teardown() in a new test class?

First of all yes, it makes a lot of sense to isolate tests that don't need the #Before or #After behavior in a separate test.
Secondly, you may want to take a look at the Spring Framework's support for running unit tests within a database transaction that is automatically rolled back at the end of each test, so that you do not have to ever worry about some tests affecting the state of an external resource, or ask questions about which tests are being run in each order, etc. Combine this with an in-memory database (like HSQL) and you won't even need to worry about having a running database somewhere to run against, making your build much more portable.

JUnit will run all methods annotated with #Before and #After for each test so you will need to split your tests into two classes.

Define your own BlockJUnit4ClassRunner:
public class WithoutBeforeAfter extends BlockJUnit4ClassRunner {
public WithoutBeforeAfter(Class<?> klass) throws InitializationError {
super(klass);
}
#Override
protected Statement withBefores(FrameworkMethod method, Object target, Statement statement) {
if(method.getName().equals("methodNameIgnore#Before")){
return statement;
}else{
return super.withBefores(method, target, statement);
}
}
#Override
protected Statement withAfters(FrameworkMethod method, Object target, Statement statement) {
if(method.getName().equals("methodNameIgnore#After")){
return statement;
}else{
return super.withAfters(method, target, statement);
}
}
}
Then use it in your test case:
#RunWith(value=WithoutBeforeAfter.class)
At least it is available in JUnit 4.8.

Related

How to cleanup h2 db after each junit test?

I am making junit tests which adds some users before each test case. The code is:
#BeforeEach
void setUp() {
saveUser();
saveEntry();
}
#Test
void saveUser() {
User user = new User();
user.setUserId(null);
user.setUsername("John");
user.setEmail("john#foo.com");
user.setPassword("password");
userService.saveUser(user);
}
#Test
void saveEntry() {
Entry entry = new Entry();
entry.setText("test text");
entry.setUserId(1L);
entryService.saveEntry(entry);
}
As you see I am using the methods that I have in my service layer to create entries and users. If I run the tests one by one there is no problem. But when I run all tests then db is not returning 1 item and returning multiple items so exception occurs.
I need to cleanup h2 db after each test with maybe #AfterEach annotation but I do not have and delete method in my code to invoke. How can I cleanup the H2 db ?
In addition to #J Asgarov answer which is correct providing you use spring-boot if you want to perform some actions before and after each test (more specifically before #Before and after #After methods) you can use #Sql annotation to execute specific sql script for example from test resources.
#Sql("init.sql")
#Sql(scripts = "clean.sql", executionPhase = Sql.ExecutionPhase.AFTER_TEST_METHOD)
public class TestClass
}
It might be handy for sequences, since they don't care of rollback.
Regarding #Transactional mentioned by #Mark Bramnik be careful, because the transaction spans for entire test method, so you cannot verify correctness of the transaction boundaries.
You've mentioned spring and it looks like you're testing DAO layer, so I assume the tests are running with SpringExtension/SpringRunner if you're on junit 4.
In this case,
Have you tried to use #Transactional on the test method? Or alternatively if all the test methods are "transactional" you can place it once on a test class.
This works as follows:
If everything is configured correctly spring will open a transaction before the test starts, and will rollback that transaction after the test ends.
The rollback is supposed to clean the inserted data automatically.
Quick googling revealed this tutorial, surely there are many others
#JpaDataTest annotating the test class will rollback every test by default
https://www.baeldung.com/spring-jpa-test-in-memory-database

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 and when to cleanup using Mockito Annotations with jUnit

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.

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