Is there any hook in Junit5 that reacts to fails in #Before* methods?
I use a #BeforeAll method to init environment for my tests. But this initialization may sometimes fail. I want to dump the environment, to find out whats wrong, but I need to do it before #After* methods are called, which will clear the environment and destroy all info.
We're talking about dozens of these #BeforeAll methods across the test suite, so doing it manually inside each method is not an option.
I've already tried these, but no luck:
TestWatcher does not work for this, since it only fires if an actual test is executed.
TestExecutionListener.executionFinished looks promising, but it fires after all the #After methods, which is too late for me.
I even tried to do it inside the #AfterAll cleanup methods, before the actual cleanup. But found no way to detect which tests were executed or if anything failed.
Any ideas?
I assume by "fails in #Before* methods" you mean exceptions? If that is the case, you could leverage the extension model as follows:
#ExtendWith(DumpEnvOnFailureExtension.class)
class SomeTest {
static class DumpEnvOnFailureExtension implements LifecycleMethodExecutionExceptionHandler {
#Override
public void handleBeforeAllMethodExecutionException(final ExtensionContext context, final Throwable ex)
throws Throwable {
System.out.println("handleBeforeAllMethodExecutionException()");
// dump env
throw ex;
}
}
#BeforeAll
static void setUpOnce() {
System.out.println("setUpOnce()");
throw new RuntimeException();
}
#Test
void test() throws Exception {
// some test
}
#AfterAll
static void tearDownOnce() {
System.out.println("tearDownOnce()");
}
}
The log will be:
setUpOnce()
handleBeforeAllMethodExecutionException()
tearDownOnce()
That is, the extension is notified if the #BeforeAll method fails with an exception. (Note that this is just an MWE, for the actual implementation you would extract DumpEnvOnFailureExtension and use it wherever needed.)
For further information, check out section "Exception Handling" in the user guide.
Related
I have a function I need to test:
#Override
public ResponseEntity<BasicResponse> myFunction(HttpServletRequest request, #RequestBody Dto dto, BindingResult result) {
try {
ValidationUtils.invokeValidator(validator, dto, result);
if (result.hasErrors()) {
// do things
} else {
//do things
}
} catch (Exception e) {
// catch
}
//return things;
}
But when I test the function it always go to the catch because of the validator, it says:
"Validator does not support Dto".
I don't care about the validation, I need to test what's inside the try, so I try to use doNothing to skip the validation but I get an error because it's void:
#Test
void TestMyFunction() {
doNothing().when(ValidationUtils.invokeValidator(validator, dto, result));
ResponseEntity<BasicResponse> response = controller.myFunction(request, dto, result);
// assert something
}
Any idea on how to proceed? I can't change the function, I can only write the test and I'm new at this. Thank you.
If ValidationUtils was an object instance that is a Mockito spy or mock, you would be able to mock it like so:
doNothing()
.when(validationUtils)
.invokeValidator(validator, dto, result);
This, unfortunately, does not seem to be the case in your test - ValidationUtils seems to be a class on which a static method is called, which Mockito can handle since version 3.4.0 (before that it was usually handled by PowerMock). thenAnswer should be used with the mockedStatic object instance, similarly to this answer, since the method's return type is void.
An important additional (but mandatory) note: mocking static methods is discouraged and should be avoided whenever possible. It slows down the tests and is a sign of bad design of the classes. The validator should be injected into the class or created using a factory, thanks to that a mocked object instance could be easily used.
I've checked that and in fact the thenAnswer part is not required to do nothing after using mockStatic on a class.
try (var mockedStatic = Mockito.mockStatic(ValidationUtils.class)) {
// test code
}
The code above makes ValidationUtils do nothing and return default values (0, false, null).
See this example (all tests pass).
public static ResponseBean call(Bean bean) throws Exception {
// statements...
IgnoreCall.ignoreMethodCall(bean);
// statements...
// return
}
With the code snippet above, is it possible to test the method ignoring invocation of IgnoreCall.ignoreMethod(Bean) without needing to place the entire statement under a boolean condition?
Here's the unit test code snippet:
#RunWith(PowerMockRunner.class)
#PrepareTest
public ClassHelperTest {
#Test
public void testCall() throws Excpetion {
// stubbing...
ResponseBean responseBean = ClassHelper.call(bean);
// verify/ies
// assert/s
}
}
Notes:
Refactoring ClassHelper.call(Bean) should be avoided. Even with a bad OO design, refactoring is costly.
Method signature is locked unless another pattern is applicable for replacement.
Tried using Mockito.when and PowerMockito.when on the target static method, stubbing didn't work on run-time debug.
As your comments indicate that changing your production code is not possible, you "simply" have to dive into the static-mocking aspects of PowerMock; as outlined here for example.
Basically you need to enable IgnoreCall for static mocking; and then you make calls to ignoreMethodCall() a no-op.
But as you keep asking: the core problem with your question is the fact that you want to mock out a static method that is void. I have a complete example below, but before that some explanations.
The point is: you call a method for two reasons:
It has a side effect
It returns a value, and maybe, causes a side effect, too
A void method can only be called for side effects. And the thing is: when you do static mocking, then that works on class level.
Meaning: you instruct PowerMock to "prevent" any of the static methods of some class from execution; you simply "erase" the side effects of all those static methods! So, by telling PowerMock to do those static mocks, all void methods are already "gone".
But as said, you might also call methods for their return value. And then is when the when() method of Mockito kicks in. You use that method to say: when that value-returning method is invoked, then do this or that.
Long story short; here is a [mcve] using the elements you asked for:
package ghostcat.test;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
class IgnoreCall {
public static void ignoreMethodCall(Object o) {
System.out.println("SHOULD NOT SHOW UP: " + o);
}
}
class CuT {
public static Object call(Object bean) {
System.out.println("statement1");
IgnoreCall.ignoreMethodCall(bean);
System.out.println("statement2");
return "whatever";
}
}
#RunWith(PowerMockRunner.class)
#PrepareForTest(IgnoreCall.class)
public class PMTest {
#Test
public void test() {
PowerMockito.mockStatic(IgnoreCall.class);
CuT.call("yeha");
}
}
As in your example ... there is IgnoreCall; used within that a static method that I just called "call".
This prints:
statement1
statement2
When I go in and comment out
// PowerMockito.mockStatic(IgnoreCall.class);
It prints:
statement1
SHOULD NOT SHOW UP: yeha
statement2
So, a simple example that should tell you exactly what you need to do.
I worked with eclipse neon, IBM java8 JDK, and simply imported all the JARs from powermock-mockito-junit-1.6.6.zip into my test project.
I have a class which has both static and non static methods and would like to write unit test cases for the same.
ClassA{
static getInstance()
{
// to do logic
}
void log()
{
system.out.print();
}
}
And the test case for classA is
ClassTest
{
public void setup()
{
PowerMockito.mockStatic(ClassA.class);
mockA = PowerMockito.mock(ClassA.class);
Mockito.when(ClassA.getInstance("user")).thenReturn(mockA);
Mockito.doNothing().when(mockA).log(Mockito.anyString(), Mockito.anyString(), Mockito.any(Exception.class), Mockito.anyMap());
enter code here
}
}
When i call log method, i am getting exception. How do we mock this?
Serious answer: don't do that.
Simply avoid writing production code that requires PowerMock; for example because you are mixing in calls to static methods.
Typically, a "need for PowerMock" directly translates to: your design needs to be improved!
You will find pretty quickly that PowerMock creates more problems that it is solving. Thus: avoid using it.
That's my test code:
public void testApplyListWhenAddTheSameIDThenReturnDuplicateEntityException(){
MyEntity entityRCM = createMyEntity(AGE_ID, WEIGHT_ID, 0L);
entityModel.addEntity(entityRCM);
MyEntity entityOPC = createMyEntity(DIFF_AGE_ID, WEIGHT_ID, 0L);
EntityCreate create = new EntityCreate(entityOPC);
List<EntityChange> changeList = new ArrayList<EntityChange>();
changeList.add(create);
try {
entityModel.apply(changeList);
fail();
}catch(DuplicateEntityException e) {
PowerMockito.verifyStatic(times(20));
LogManager.error(Mockito.<Logger>anyObject(),Mockito.anyString(),Mockito.<DuplicateEntityException>anyObject());
}
}
The problem is here:
PowerMockito.verifyStatic(times(20));
LogManager.error(Mockito.<Logger>anyObject(),Mockito.anyString(),Mockito.<DuplicateEntityException>anyObject());
I want to verify a static method error in class LogManager, but how can I verify this method for twenty times but it doesn't fail.
Solved in the comments:
Did you add #PrepareForTest and mockStatic? If not, then you may have set up your matchers and static call but PowerMock never sees the actual call to mock before your test completes.
For context, PowerMock mocks static classes by intercepting the classloader and loading a replacement class that calls PowerMock-provided implementations instead of the originals. Unless you add the right preparation, PowerMock won't replace the class, so it won't count static method calls or identify the method to verify, and the test will complete before the verification call ever actually happens.
In my webdriver script I have the three methods
setup, test and tearDown
following the junit convention.
In the test method I have few asserts like this
#Test
public void testStudentHome() throws Exception {
String classCode = "I6OWW";
Utilities.studentSignin(driver, baseUrl);
assertEquals(true, sth.openNotification());
assertEquals("My Scores", sth.myScores(true));
}
The sth is the PageObject on which I am performing the tests and that I have created in the setup method.
I am calling all these three methods from a main method like this:
public static void main(String[] args) {
StudentHomeTest sht = new StudentHomeTest();
try {
sht.setup();
sht.testStudentHome();
sht.tearDown();
} catch (Exception ex) {
Logger.getLogger(StudentHomeTest.class.getName()).log(Level.SEVERE, null, ex);
sht.tearDown();
}
}
Now while running the test if some assertion fails the test method should (this is what I expect) throw an exception and the main method should call the tearDown method. But this does not happen. and the browser window continues to stay there.
I am using the netbeans ide for running the test.
following the junit convention
If you follow the jUnit convention, then you will know that teardown methods belong in the #After method as this method will always run after your tests.
create a new method with the #After jUnit annotation.
#After
public void tearDown() {
sht.tearDown();
}
Edit
You know what, I believe that you are running into a classic issue of assertEquals in jUnit.
Stolen from this answer...:
JUnit calls the .equals() method to determine equality in the method assertEquals(Object o1, Object o2).
So, you are definitely safe using assertEquals(string1, string2). (Because Strings are Objects)
--
Instead of using assertEquals on these calls, use assertTrue() instead.
assertTrue(sth.openNotification());
assertTrue("My Scores".equals(sth.myScores(true)));
AssertionError doesn't extend Exception - it's a Throwable.
But in any case, you should have
try {
sht.setup();
sht.testStudentHome();
} finally {
sht.tearDown();
}
No need for a catch block. main can throw Exception.