I have a static method that is mocked using PowerMock to throw an exception. (It deletes files.) Unfortunately, during my #After (after-each-test) method, I need to call this method without the mocks. How can I umock a method?
I don't see an equivalent to Mockito.reset(). [ Ref: mockito : how to unmock a method? ]
Example:
#RunWith(PowerMockRunner.class)
#PrepareForTest(PathUtils.class) // Important: This class has a static method we want to mock.
public class CleaningServiceImplTest2 extends TestBase {
public static final File testDirPath = new File(CleaningServiceImplTest2.class.getSimpleName());
#BeforeClass
public static void beforeAllTests() throws PathException {
recursiveDeleteDirectory(testDirPath);
}
#AfterClass
public static void afterAllTests() throws PathException {
recursiveDeleteDirectory(testDirPath);
}
private File randomParentDirPath;
private CleaningServiceImpl classUnderTest;
#Before
public void beforeEachTest() {
randomParentDirPath = new File(testDirPath, UUID.randomUUID().toString()).getAbsoluteFile();
classUnderTest = new CleaningServiceImpl(randomParentDirPath);
}
#After
public void afterEachTest() throws PathException {
recursiveDeleteDirectory(randomParentDirPath);
}
public static void recursiveDeleteDirectory(File dirPath) throws PathException {
// calls PathUtils.removeFile(...)
}
#Test
public void run_FailWhenCannotRemoveFile() throws IOException {
// We only want to mock one method. Use spy() and not mockStatic().
PowerMockito.spy(PathUtils.class);
// These two statements are tightly bound.
PowerMockito.doThrow(new PathException(PathException.PathExceptionReason.UNKNOWN, randomParentDirPath, null, "message"))
.when(PathUtils.class);
PathUtils.removeFile(Mockito.any(File.class));
classUnderTest.run();
}
}
This took me a while to figure out, so I am answering my own question.
AFAIK, you need to "undo" each mock. Mockito.reset() will not work with Class<?> references. At the end of the test method, add:
// Undo the mock above because we need to call PathUtils.removeFile() within #After.
PowerMockito.doCallRealMethod().when(PathUtils.class);
PathUtils.removeFile(Mockito.any(File.class));
The only way you can undo mocking of a static method with PowerMock is when you mock a class at the beginning of a test and then undo the mock at the end of a test. It doesn't matter if you use SPY or a regular mocking.
Tested with:
"org.powermock" % "powermock" % "1.5" % Test,
"org.powermock" % "powermock-api-mockito" % "1.6.1" % Test,
Test class
package mytests;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import static org.fest.assertions.Assertions.assertThat;
#RunWith(PowerMockRunner.class)
#PrepareForTest({StaticTest.class})
public class TestTest {
#Before
public void checkIfOriginalMethodGetsCalled() {
// PowerMockito.mockStatic(StaticTest.class); if you do this in #Before you are not going to be able to undo it
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
assertThat(StaticTest.otherStaticMethod()).isEqualTo("SPY TEST ORIGINAL");
}
#Test
public void test1() {
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
}
#Test
public void test3_mocking() {
mock(); // mock or spy static methods in a test, not in #Before
Mockito.when(StaticTest.staticMethod()).thenReturn("MOCKED VALUE");
assertThat(StaticTest.staticMethod()).isEqualTo("MOCKED VALUE");
assertThat(StaticTest.otherStaticMethod()).isEqualTo("SPY TEST ORIGINAL");
undoMock(); // undo the mock at the end of each test, not in #After
}
private void mock() {
// PowerMockito.mockStatic(StaticTest.class); both, spy and mockStatic work ok
PowerMockito.spy(StaticTest.class);
}
private void undoMock() {
PowerMockito.doCallRealMethod().when(StaticTest.class);
assertThat(StaticTest.staticMethod()).isNull(); // the undo is going to work in the next test, not here yet.
}
#Test
public void test2() {
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
}
#After
public void checkIfOriginalMethodGetsCalled_AfterMockUndo() {
// undoMock(); in #After doesn't work with static methods
assertThat(StaticTest.staticMethod()).isEqualTo("ORIGINAL VALUE");
assertThat(StaticTest.otherStaticMethod()).isEqualTo("SPY TEST ORIGINAL");
}
}
class StaticTest {
public static String staticMethod() {
return "ORIGINAL VALUE";
}
public static String otherStaticMethod() {
return "SPY TEST ORIGINAL";
}
}
Related
Public Class DailyJob(){
public void runJob(ScheduleJob currentJob) {
try {
int employee = employeeService.getEmployeeNum();
JobPerformance jobPerformance = performanceService.searchJobPerformance(employee);
if(jobPerformance.size() >0 ) {
currentJob.setRecord("success");
}
else {
currentJob.setRecord("failed");
}
}
catch{
//catch error
}
}
}
By now I want to write a Junit test for runJob(). But how can I setup the value I prefer into 'employee' parameter in Junit Test while I test runJob()? Anyone know how to implement it?
You can use Mockito. You setup stubbing, which will return desired value. Also you can stub for multiple calls by
.thenReturn(9, 10, 7);
import org.junit.jupiter.api.Test;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class MyTest {
#Test
void test() {
EmployeeService employeeService = mock(EmployeeService.class);
when(employeeService.getEmployeeNum()).thenReturn(9);
}
}
For example I have the following classes below:
public class TesteEstatico {
public static String teste(){
return "FOO";
}
}
And I have a class that uses her method:
public class UsaTesteEstatico {
public String metodoParaTeste1 (){
return TesteEstatico.teste() + " BAR ";
}
public String metodoParaTeste2 (){
return "FOO "+TesteEstatico.teste() + " BAR ";
}
}
Test class:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class) public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#Test
void teste1(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.mockStatic(TesteEstatico.class);
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
Error I get when trying to run the tests:
org.mockito.exceptions.base.MockitoException:
For TesteEstatico, static mocking is already registered in the current thread
To create a new mock, the existing static mock registration must be deregistered
Versions of the libs that are in the project:
junit-jupiter 5.5.2
mockito-junit-jupiter 3.2.14
mockito-inline 3.2.14
Any idea how to solve this, i've tried a few things but nothing successful.
NOTE: I cannot change or add any new libraries as it is a restricted project.
You should use try-with-resources block in each of the tests to close the mockStatic.
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
#Test
void teste1(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
}
#Test
void teste2(){
try (var ms = Mockito.mockStatic(TesteEstatico.class)) {
Mockito.when(TesteEstatico.teste()).thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
}
Note on mockStatic in #BeforeAll
Using #BeforeAll is a trap and bad advice.
You should strive for independent tests that don't affect each other.
This is not the case for mockStatic called in #BeforeAll, as stubbing from test methods outlive the test methods.
For example
// BAD CODE DONT USE
public class UsaTesteEstaticoTest {
UsaTesteEstatico usaTesteEstatico = new UsaTesteEstatico();
static MockedStatic<TesteEstatico> ms;
#BeforeAll
public static void init() {
ms = Mockito.mockStatic(TesteEstatico.class);
}
#AfterAll
public static void close() {
ms.close();
}
#Test
void teste1() {
Mockito.when(TesteEstatico.teste()).thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2() {
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
teste2 prints:
FOO BANANA BAR if run after teste1
FOO null BAR if run separately
This is precisely what you want to avoid.
you need to use static block to mock it.
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class UsaTesteEstaticoTest {
#InjectMocks
UsaTesteEstatico usaTesteEstatico;
#BeforeAll
public static void init(){
Mockito.mockStatic(TesteEstatico.class);
}
#Test
void teste1(){
Mockito.when(TesteEstatico.teste())
.thenReturn("BANANA");
String res = usaTesteEstatico.metodoParaTeste1();
System.out.println(res);
}
#Test
void teste2(){
Mockito.when(TesteEstatico.teste())
.thenReturn("LARANJA");
String res = usaTesteEstatico.metodoParaTeste2();
System.out.println(res);
}
}
I have a problem with the mockito.
Code to my program
public boolean bajaContribuyente(String dni){
Contribuyente c = em.find(Contribuyente.class, dni);
if(c!=null){
em.remove(c);
return true;
}
return false;
}
And the test:
#BeforeClass
public static void setUpBeforeClass()throws Exception{
contribuyenteDAO.setEm(em);;
when(contribuyenteD.getDni()).thenReturn("4");
when(em.find(Contribuyente.class, "4")).thenReturn(contribuyenteD);
}
#Test
public void testBajaContribuyente(){
contribuyenteDAO.bajaContribuyente("4");
verify(em).find(Contribuyente.class, "4");
verify(em).remove(contribuyenteD);
}
JUnit say that missing method call for verify(mock), but i dont know why
You likely need to add a static import of Mockito's methods (e.g. verify), like the following:
import static org.mockito.Mockito.*;
I'm testing extensively with JUnit and sometimes - while debugging my code - I want (temporary) only run a single #Test of my #RunWith(Arquillian.class) test class. Currently I'm adding a #Ignore to all other tests and wondering if something like #IgnoreOther does exist.
Are there better solutions to ignore all other tests?
The simplest way is to replace all #Test to //###$$$#Test. Then when your debugging is finished replace //###$$$#Test to #Test.
Moreover typically IDEs allow running one test only. For example in Eclipse you can do it from Outline view.
Just my two cents. You can try to use Junit Rules as #srkavin suggested.
Here is an example.
package org.foo.bar;
import org.junit.rules.MethodRule;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.Statement;
public class SingleTestRule implements MethodRule {
private String applyMethod;
public SingleTestRule(String applyMethod) {
this.applyMethod = applyMethod;
}
#Override
public Statement apply(final Statement statement, final FrameworkMethod method, final Object target) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
if (applyMethod.equals(method.getName())) {
statement.evaluate();
}
}
};
}
}
package org.foo.bar;
import org.junit.Assert;
import org.junit.Rule;
import org.junit.Test;
public class IgnoreAllTest {
#Rule
public SingleTestRule test = new SingleTestRule("test1");
#Test
public void test1() throws Exception {
System.out.println("test1");
}
#Test
public void test2() throws Exception {
Assert.fail("test2");
}
#Test
public void test3() throws Exception {
Assert.fail("test3");
}
}
Test rules (JUnit 4.7+) will help. For example, you can write a rule that ignores all #Test methods except one with a specific name.
The answer from srkavin (and mijer) is correct, but the code is deprecated from JUnit 4.9. The interface and the method signature have changed. I want to provide this for others interested in this issue.
public class IgnoreOtherRule implements TestRule
{
private String applyMethod;
public IgnoreOtherRule(String applyMethod){
this.applyMethod = applyMethod;
}
#Override
public Statement apply(final Statement statement, final Description description)
{
return new Statement()
{
#Override
public void evaluate() throws Throwable {
if (applyMethod.equals(description.getMethodName())) {
statement.evaluate();
}
}
};
}
}
Is there a way in JUnit to detect within an #After annotated method if there was a test failure or error in the test case?
One ugly solution would be something like that:
boolean withoutFailure = false;
#Test
void test() {
...
asserts...
withoutFailure = true;
}
#After
public void tearDown() {
if(!withoutFailuere) {
this.dontReuseTestenvironmentForNextTest();
}
}
This is ugly because one need to take care of the "infrastructure" (withoutFailure flag) in the test code.
I hope that there is something where I can get the test status in the #After method!?
If you are lucky enough to be using JUnit 4.9 or later, TestWatcher will do exactly what you want.
Share and Enjoy!
I extend dsaff's answer to solve the problem that a TestRule can not execute some code snipped between the execution of the test-method and the after-method. So with a simple MethodRule one can not use this rule to provide a success flag that is use in the #After annotated methods.
My idea is a hack! Anyway, it is to use a TestRule (extends TestWatcher). A TestRule will get knowledge about failed or success of a test. My TestRule will then scan the class for all Methods annotated with my new AfterHack annotations and invoke that methods with a success flag.
AfterHack annotation
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface AfterHack {}
AfterHackRule
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class AfterHackRule extends TestWatcher {
private Object testClassInstance;
public AfterHackRule(final Object testClassInstance) {
this.testClassInstance = testClassInstance;
}
protected void succeeded(Description description) {
invokeAfterHackMethods(true);
}
protected void failed(Throwable e, Description description) {
invokeAfterHackMethods(false);
}
public void invokeAfterHackMethods(boolean successFlag) {
for (Method afterHackMethod :
this.getAfterHackMethods(this.testClassInstance.getClass())) {
try {
afterHackMethod.invoke(this.testClassInstance, successFlag);
} catch (IllegalAccessException | IllegalArgumentException
| InvocationTargetException e) {
throw new RuntimeException("error while invoking afterHackMethod "
+ afterHackMethod);
}
}
}
private List<Method> getAfterHackMethods(Class<?> testClass) {
List<Method> results = new ArrayList<>();
for (Method method : testClass.getMethods()) {
if (method.isAnnotationPresent(AfterHack.class)) {
results.add(method);
}
}
return results;
}
}
Usage:
public class DemoTest {
#Rule
public AfterHackRule afterHackRule = new AfterHackRule(this);
#AfterHack
public void after(boolean success) {
System.out.println("afterHack:" + success);
}
#Test
public void demofails() {
Assert.fail();
}
#Test
public void demoSucceeds() {}
}
BTW:
1) Hopefully there is a better solution in Junit5
2) The better way is to use the TestWatcher Rule instead of the #Before and #After Method at all (that is the way I read dsaff's answer)
#see
I don't know any easy or elegant way to detect the failure of a Junit test in an #After method.
If it is possible to use a TestRule instead of an #After method, one possibility to do it is using two chained TestRules, using a TestWatcher as the inner rule.
Example:
package org.example;
import static org.junit.Assert.fail;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExternalResource;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.rules.TestWatcher;
import org.junit.runner.Description;
public class ExampleTest {
private String name = "";
private boolean failed;
#Rule
public TestRule afterWithFailedInformation = RuleChain
.outerRule(new ExternalResource(){
#Override
protected void after() {
System.out.println("Test "+name+" "+(failed?"failed":"finished")+".");
}
})
.around(new TestWatcher(){
#Override
protected void finished(Description description) {
name = description.getDisplayName();
}
#Override
protected void failed(Throwable e, Description description) {
failed = true;
}
})
;
#Test
public void testSomething(){
fail();
}
#Test
public void testSomethingElse(){
}
}