PowerMock prepare a class for test without using #PrepareForTest annotation - java

I have inherited a complex JUnit 4 test class which uses
#RunWith(MockitoJUnitRunner.class)
Because of a change in implementation I need to use some features from PowerMock to mock static and private methods. But when I try to switch at class level to
#RunWith(PowerMockRunner.class)
#PrepareForTest(MyClass.class)
I get lots of errors because Mockito annotations are not being properly handled.
The question is: can I keep the #RunWith(MockitoJUnitRunner.class) annotation and do programmatically the same as #PrepareForTest(MyClass.class) just when I need it for a class?

Related

How to ignore a quarkus test

I am testing my Quarkus application, and I would like to ignore some of my tests.
The test class is annotated with #io.quarkus.test.junit.QuarkusTest, and each method with #org.junit.jupiter.api.Test
I'm trying to use the #org.junit.Ignore annotation, but it's not working, the ignored tests are executed anyway.
This is the code:
#QuarkusTest
#TestHTTPEndpoint(MyResource::class)
class MyResourceTest {
#Test
#Ignore
fun `to be ignored`() {
assertTrue(false)
}
}
Does anyone know how can I achieve this?
You can use #Disabled annotation
You can also conditionally run tests with assumptions.

Issues with #Rule and PowerMockRule

I am using
#Rule
public PowerMockRule rule = new PowerMockRule();
in one of my test file. Now when I am removing this part of code several test cases starts failing which are in different folders and having no direct relationship with this file.
What could be the problem?
Refer to the below wiki link for more details.
Technically, instead of using #RunWith(PowerMockRunner.class) , you can use PowerMockRuleas shown in the below example.
So, when you remove PowerMockRule, your tests are gonna fail because you will not have #RunWith(PowerMockRunner.class) in your tests.
https://github.com/powermock/powermock/wiki/powermockrule
Bootstrapping using a JUnit Rule
Feature avaliable since PowerMock 1.4 Since version 1.4
It's possible to bootstrap PowerMock using a JUnit Rule instead of
using the PowerMockRunner and the RunWith
annotation. This allows you to use other JUnit runners while still
benefiting from PowerMock's functionality. You do this by specifying:
With PowerMockRule
#PrepareForTest(X.class);
public class MyTest {
#Rule
PowerMockRule rule = new PowerMockRule();
// Tests goes here
...
}
Without PowerMockRule
#RunWith(PowerMockRunner.class)
#PrepareForTest(X.class);
public class MyTest {
// Tests goes here
...
}

Using MockitoExtension in JUnit 5 [duplicate]

How can I use injection with Mockito and JUnit 5?
In JUnit4 I can just use the #RunWith(MockitoJUnitRunner.class) Annotation. In JUnit5 is no #RunWith Annotation?
There are different ways to use Mockito - I'll go through them one by one.
Manually
Creating mocks manually with Mockito::mock works regardless of the JUnit version (or test framework for that matter).
Annotation Based
Using the #Mock-annotation and the corresponding call to MockitoAnnotations::initMocks
to create mocks works regardless of the JUnit version (or test framework for that matter but Java 9 could interfere here, depending on whether the test code ends up in a module or not).
Mockito Extension
JUnit 5 has a powerful extension model and Mockito recently published one under the group / artifact ID org.mockito : mockito-junit-jupiter.
You can apply the extension by adding #ExtendWith(MockitoExtension.class) to the test class and annotating mocked fields with #Mock. From MockitoExtension's JavaDoc:
#ExtendWith(MockitoExtension.class)
public class ExampleTest {
#Mock
private List list;
#Test
public void shouldDoSomething() {
list.add(100);
}
}
The MockitoExtension documentation describes other ways to instantiate mocks, for example with constructor injection (if you rpefer final fields in test classes).
No Rules, No Runners
JUnit 4 rules and runners don't work in JUnit 5, so the MockitoRule and the Mockito runner can not be used.
Use Mockito's MockitoExtension. The extension is contained in a new artifact mockito-junit-jupiter:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
It allows you to write tests as you would have with JUnit 4:
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
#ExtendWith(MockitoExtension.class)
class MyTest {
#Mock
private Foo foo;
#InjectMocks
private Bar bar; // constructor injection
...
}
There are different ways to do but the cleaner way and that also respects the JUnit 5 philosophy is creating a org.junit.jupiter.api.extension.Extension for Mockito.
1) Creating mocks manually makes lose the benefit of additional Mockito checks to ensure you use correctly the framework.
2) Calling MockitoAnnotations.initMocks(this) in every test classes is boiler plate code that we could avoid.
And making this setup in an abstract class is not a good solution either.
It couples every test classes to a base class.
If then you need a new base test class for good reasons, you finish with a 3- level class hierarchy. Please avoid that.
3) Test Rules is a JUnit 4 specificity.
Don't even think of that.
And the documentation is clear about that :
However, if you intend to develop a new extension for JUnit 5 please
use the new extension model of JUnit Jupiter instead of the rule-based
model of JUnit 4.
4) Test Runner is really not the way to extend the JUnit 5 framework.
JUnit 5 simplified the hell of the Runners of JUnit 4 by providing an extension model for writing tests thanks to JUnit 5 Extensions.
Don't even think of that.
So favor the org.junit.jupiter.api.extension.Extension way.
EDIT : Actually, Mockito bundles a jupiter extension : mockito-junit-jupiter
Then, very simple to use :
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class FooTest {
...
}
Here is an addition to the excellent answer of Jonathan.
By adding as dependency the mockito-junit-jupiter artifact, the use of #ExtendWith(MockitoExtension.class) produced the following exception as the test is executed :
java.lang.NoSuchMethodError:
org.junit.platform.commons.support.AnnotationSupport.findAnnotation(Ljava/util/Optional;Ljava/lang/Class;)Ljava/util/Optional;
THe problem is that mockito-junit-jupiter depends on two independent libraries.
For example for mockito-junit-jupiter:2.19.0 :
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.19.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.1.0</version>
<scope>runtime</scope>
</dependency>
The problem was I used junit-jupiter-api:5.0.1.
So as junit-jupiter-api moves still often in terms of API, make sure you depend on the same version of junit-jupiter-api that mockito-junit-jupiter depends on.
You have to use the new #ExtendWith annotation.
Unfortunately there is no extension released yet.
On github you can see a beta implementation for the extension. as a example demo test.

How to use Mockito with JUnit5

How can I use injection with Mockito and JUnit 5?
In JUnit4 I can just use the #RunWith(MockitoJUnitRunner.class) Annotation. In JUnit5 is no #RunWith Annotation?
There are different ways to use Mockito - I'll go through them one by one.
Manually
Creating mocks manually with Mockito::mock works regardless of the JUnit version (or test framework for that matter).
Annotation Based
Using the #Mock-annotation and the corresponding call to MockitoAnnotations::initMocks
to create mocks works regardless of the JUnit version (or test framework for that matter but Java 9 could interfere here, depending on whether the test code ends up in a module or not).
Mockito Extension
JUnit 5 has a powerful extension model and Mockito recently published one under the group / artifact ID org.mockito : mockito-junit-jupiter.
You can apply the extension by adding #ExtendWith(MockitoExtension.class) to the test class and annotating mocked fields with #Mock. From MockitoExtension's JavaDoc:
#ExtendWith(MockitoExtension.class)
public class ExampleTest {
#Mock
private List list;
#Test
public void shouldDoSomething() {
list.add(100);
}
}
The MockitoExtension documentation describes other ways to instantiate mocks, for example with constructor injection (if you rpefer final fields in test classes).
No Rules, No Runners
JUnit 4 rules and runners don't work in JUnit 5, so the MockitoRule and the Mockito runner can not be used.
Use Mockito's MockitoExtension. The extension is contained in a new artifact mockito-junit-jupiter:
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>4.5.1</version>
<scope>test</scope>
</dependency>
It allows you to write tests as you would have with JUnit 4:
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
#ExtendWith(MockitoExtension.class)
class MyTest {
#Mock
private Foo foo;
#InjectMocks
private Bar bar; // constructor injection
...
}
There are different ways to do but the cleaner way and that also respects the JUnit 5 philosophy is creating a org.junit.jupiter.api.extension.Extension for Mockito.
1) Creating mocks manually makes lose the benefit of additional Mockito checks to ensure you use correctly the framework.
2) Calling MockitoAnnotations.initMocks(this) in every test classes is boiler plate code that we could avoid.
And making this setup in an abstract class is not a good solution either.
It couples every test classes to a base class.
If then you need a new base test class for good reasons, you finish with a 3- level class hierarchy. Please avoid that.
3) Test Rules is a JUnit 4 specificity.
Don't even think of that.
And the documentation is clear about that :
However, if you intend to develop a new extension for JUnit 5 please
use the new extension model of JUnit Jupiter instead of the rule-based
model of JUnit 4.
4) Test Runner is really not the way to extend the JUnit 5 framework.
JUnit 5 simplified the hell of the Runners of JUnit 4 by providing an extension model for writing tests thanks to JUnit 5 Extensions.
Don't even think of that.
So favor the org.junit.jupiter.api.extension.Extension way.
EDIT : Actually, Mockito bundles a jupiter extension : mockito-junit-jupiter
Then, very simple to use :
import org.mockito.junit.jupiter.MockitoExtension;
#ExtendWith(MockitoExtension.class)
public class FooTest {
...
}
Here is an addition to the excellent answer of Jonathan.
By adding as dependency the mockito-junit-jupiter artifact, the use of #ExtendWith(MockitoExtension.class) produced the following exception as the test is executed :
java.lang.NoSuchMethodError:
org.junit.platform.commons.support.AnnotationSupport.findAnnotation(Ljava/util/Optional;Ljava/lang/Class;)Ljava/util/Optional;
THe problem is that mockito-junit-jupiter depends on two independent libraries.
For example for mockito-junit-jupiter:2.19.0 :
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>2.19.0</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.1.0</version>
<scope>runtime</scope>
</dependency>
The problem was I used junit-jupiter-api:5.0.1.
So as junit-jupiter-api moves still often in terms of API, make sure you depend on the same version of junit-jupiter-api that mockito-junit-jupiter depends on.
You have to use the new #ExtendWith annotation.
Unfortunately there is no extension released yet.
On github you can see a beta implementation for the extension. as a example demo test.

Mockito asks to add #PrepareForTest for the class even after adding #PrepareForTest

I have the following simple code. I have a class (TestClass) and I want to test "someMethod". There is an external static method which is called by my "someMethod".
I want to Powermock that static method to return me some dummy object.
I have the #PrepareForTest(ExternalClass.class) in the begining, but when I execute it gives the error:
The class ExternalClass not prepared for test.
To prepare this class, add class to the '#PrepareForTest' annotation.
In case if you don't use this annotation, add the annotation on class or method level.
Please help me to point out what is wrong with the way I have used #PrepareForTest
#RunWith(PowerMockRunner.class)
#PrepareForTest(ExternalClass.class)
public class xyzTest {
#Mock
private RestTemplate restTemplate;
#Mock
private TestClass testClass;
#BeforeClass
private void setUpBeforeClass() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testSuccessCase() {
Boolean mockResponse = true;
ResponseEntity<Boolean> response = new ResponseEntity<Boolean>(mockResponse, HttpStatus.OK);
SomeClass someClass = new SomeClass("test", "1.0.0", "someUrl", "someMetaData");
PowerMockito.mockStatic(ExternalClass.class);
Mockito.when(restTemplate.postForEntity(any(String.class), any(String.class), eq(Boolean.class))).thenReturn(response);
Mockito.when(ExternalClass.getSomeClass(any(String.class))).thenReturn(someClass);
Boolean result = testClass.someMethod("test");
Assert.isTrue(result);
Mockito.verify(restTemplate, times(1)).postForObject(any(String.class), any(String.class), any());
}
}
Make sure you add #RunWith(PowerMockRunner.class) to the top of your class as well.
::edit:: two years later...
Don't ever use PowerMockito, you shouldn't need to.
If you do need to, you have most likely broken the SOLID principles and your design is wrong.
Fix your design instead.
As with the last answer, my problem was also mixing the Test annotation from TestNG instead of Junit Test.
import org.junit.Test; // works
import org.testng.annotations.Test // did not work
Very abstruse error and I spent more than 5 hrs debugging :(
For those trying to get this working with Junit 5, If your using the powermock-module-junit4 beta release which claims to be compatible with 4+, the library will still not recognize:
import org.junit.jupiter.api.Test;
and it will throw a:
org.powermock.api.mockito.ClassNotPreparedException
when #PrepareForTest is applied on the class you want to static mock. If you want to use PowerMock, you will have to go back to Junit 4 or create a MockWrapper for your static method at this time.
PowerMock 2.0: Github Roadmap
While the top-rated answer here is correct without a doubt, this does not answer the question of why is that needed; or, for example, why the same thing would not work with adding #RunWith(MockitoJUnitRunner.class).
The thing is PowerMockRunner uses instrumentation API under the hood, via
javassist library, this allows to alter the classes, like remove final or mock static (non-compile time constants).
In the process of modifying (instrumenting) a certain class, they add an interface to that, called PowerMockModified. It is a marker interface that denotes that a certain byte-code instrumentation took place. Later in the code, they simply check if the class that you use in #PrepareForTest was actually instrumented in some way or not, via such a method:
private boolean isModifiedByPowerMock() {
return PowerMockModified.class.isAssignableFrom(this.type);
}
In turns out that PowerMockRunner does some instrumentation, while MockitoJUnitRunner does not; thus the error you get.
I had the same error, resolved this by adding
#Rule
public PowerMockRule rule = new PowerMockRule();
inside the test class.
If above answers don't work try extends PowerMockTestCase. This trick worked for me.
Example:
public class xyzTest extends PowerMockTestCase
check if import org.junit.Test; package has imported and not that api jupiter one.
I had the same error but resolved it. My problem was that I included powermock-module-junit4 but included my test annotation from TestNG instead of Junit.
I had the same error. I was using TestNG to run the tests. I had to use the following method to fix the above issue.
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
For testNG there are 2 options as follows :
Using ObjectFactory as below:
#ObjectFactory
public IObjectFactory getObjectFactory() {
return new PowerMockObjectFactory();
}
Test class extending extends org.powermock.modules.testng.PowerMockTestCase
My gradle was using Junit 5.
test {
useJUnitPlatform()
}
I was able to debug this. By having breakpoints in PowerMockRunner methods.
It was not invoked. Moreover JUnit 5 is not supported with PowerMockito.
Looks like JUnit5 runs without #ExtendWith.
Make sure you are using powermock2. I had this problem when I was using powermock.
Use
import org.powermock2.api.mockito.PowerMockito;

Categories

Resources