NotAMockException exception when trying to verify a static method with Powermockito - java

I use PowerMock to test a static method as mentioned its documentation.
As far as I see, there may be a bug, but I am not sure:
Static mocking broken for Mockito >= 2.26.1
...
I tried the workarounds mentioned on the following pages, however it does not fix the problem and some of them cannot be applicable as they are outdated.
NotAMockException when trying to verify a static method
verifyStatic get NotAMockExcption from mockito
However, I get "Argument passed to verify() is of type Class and is not a mock!" error. Here is the service method that I am testing and test method:
service:
// I want to test this method
public CommandDTO create(EmployeeRequest request) {
// ...
log();
return CommandDTO.builder().uuid(employee.getUuid()).build();
}
private void log() {
LoggingUtils.info("Created...");
}
test:
#RunWith(PowerMockRunner.class)
#PrepareForTest(LoggingUtils.class)
public class EMployeeServiceImplTest {
#Test
public void unit_test() {
// ...
PowerMockito.mockStatic(LoggingUtils.class);
employeeService.create(request);
PowerMockito.verifyStatic(LoggingUtils.class); // throws error
LoggingUtils.info(any());
}
}
Here are libraries and versions:
pom.xml:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>3.4.6</version>
<scope>test</scope>
</dependency>

Since you asked in another comment, here's a pattern I've used in the past to prevent the need for static mocking:
Imagine we have a static method...
public class SomeClass {
public static String doSomething(int x) { ... }
}
Now imagine our code using it like this...
public class MyClass {
public void someMethod() {
String xyz = SomeClass.doSomething(123);
...
}
}
If we now needed to mock that SomeStaticClass.doSomething(123) call, we need static mocking.
An alternative is a delegator:
public class MyDelegator {
public String doSomething(int x) {
return SomeClass.doSomething(x);
}
}
Now you can use that instead in your class:
public class MyClass {
private final MyDelegator myDelegator;
public MyClass(MyDelegator myDelegator) { this.myDelegator = myDelegator; }
public void someMethod() {
String xyz = myDelegator.doSomething(123);
...
}
}
And voila, you can simply mock the MyDelegator object instead of having to care that the original implementation was a static call.
Of course, this doesn't solve the underlying code smell, but it can help you to work around it in cases where you cannot refactor the static code itself.

Let me suggest a different approach altogether because I see you already use Mockito version 3.4.6 .
Since Mockito >= 3.4.0 you are able to mock static methods directly. This means you can completely get rid of the PowerMock dependency.
Also, AFAIK PowerMock does not support JUnit5. This solution will allow you to upgrade your JUnit test framework to version 5 without issues which I also highly recommend.
Static mocking using Mockito does require you to use the mockito-inline dependency over mockito-core but, because mockito-inline depends on mockito-core, Maven will also download the mockito-core package. Please note that the Mockito documentation states that, at one point in the future, they might abolish this package when they pull all these
"experimental" features to the core package.
Next to that, you should also replace #RunWith(PowerMockRunner.class) with #RunWith(MockitoJUnitRunner.class)
This is how you use it.
You can either define the mock per test method like so using a try-with-resources statement that automatically calls close
try (MockedStatic<Files> filesMock = Mockito.mockStatic(Files.class)) {
filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
// Call logic
}
Or you can define it for all tests in a #Before method because you use jUnit4.
private MockedStatic<Files> filesMock;
#Before
public void init() {
filesMock = org.mockito.Mockito.mockStatic(Files.class);
}
#After
public void teardown() {
filesMock.close();
}
#Test
void test() {
filesMock.when(() -> Files.copy(any(Path.class), any(OutputStream.class))).thenReturn(1L);
}
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#mockito-inline
https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html#static_mocks

Related

What is the equivalent of ExternalResource and TemporaryFolder in JUnit 5?

According to the JUnit 5 User Guide, JUnit Jupiter provides backwards compatibility for some JUnit 4 Rules in order to assist with migration.
As stated above, JUnit Jupiter does not and will not support JUnit 4 rules natively. The JUnit team realizes, however, that many organizations, especially large ones, are likely to have large JUnit 4 codebases including custom rules. To serve these organizations and enable a gradual migration path the JUnit team has decided to support a selection of JUnit 4 rules verbatim within JUnit Jupiter.
The guide goes on to say that one of the rules is ExternalResource, which is a parent for TemporaryFolder.
However, the guide unfortunately doesn't go on to say what the migration path is, or what the equivalent is for those writing new JUnit 5 tests. So what should we use?
Interesting article by author of TemporaryFolderExtension for JUnit5
and
his code repo on github
JUnit5.0.0 is now in general release so let's hope they turn their attention to making the experimental stuff production-ready.
Meanwhile, it seems the TemporaryFolder rule will still work with JUnit5 docs
use this:
#EnableRuleMigrationSupport
public class MyJUnit5Test {
and this:
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-migrationsupport</artifactId>
<version>5.0.0</version>
</dependency>
As far as I understood, there can be no one to one mapping from ExternalResource to an equivalent in JUnit5. The concepts just don't fit. In JUnit4, the ExternalResource basically gives you a before and an after callback, but within the rule, you have no control about what before and after actually means. You could use it with #Rule or with #ClassRule.
In JUnit5, the extension is defined to hook in specific extension points and thus the 'when' is well defined.
Another difference in concepts would be, that you can have a state in JUnit4 rules, but your JUnit5 extensions shouldn't have any state. Instead, all state should go to the execution context.
Nevertheless, here is an option I came along with, where before and after relates to each test method:
public abstract class ExternalResourceExtension
implements BeforeTestExecutionCallback, AfterTestExecutionCallback {
#Override
public void beforeTestExecution(ExtensionContext context) throws Exception {
before(context);
}
#Override
public void afterTestExecution(ExtensionContext context) throws Exception {
after(context);
}
protected abstract void before(ExtensionContext context);
protected abstract void after(ExtensionContext context);
}
JUnit 5.4 comes with a built-in extension to handle temporary directories in tests.
#org.junit.jupiter.api.io.TempDir annotation can be used in order to annotate class field or a parameter in a lifecycle (e.g. #BeforeEach) or test method of type File or Path.
import org.junit.jupiter.api.io.TempDir;
#Test
void writesContentToFile(#TempDir Path tempDir) throws IOException {
// arrange
Path output = tempDir
.resolve("output.txt");
// act
fileWriter.writeTo(output.toString(), "test");
// assert
assertAll(
() -> assertTrue(Files.exists(output)),
() -> assertLinesMatch(List.of("test"), Files.readAllLines(output))
);
}
You can read more on this in my blog post, where you will find some more examples on utilizing this built-in extension: https://blog.codeleak.pl/2019/03/temporary-directories-in-junit-5-tests.html.
The documentation for that is still in the making - see pull request #660.
Temporary folders now have a solution in the way of #TempDir. However, what about the idea behind ExternalResources in general? Perhaps it's for a mock database, a mock HTTP connection, or some other custom resource you want to add support for?
The answer, it turns out is you can use the #RegisterExtension annotation to achieve something quite similar.
Example of use:
/**
* This is my resource shared across all tests
*/
#RegisterExtension
static final MyResourceExtension MY_RESOURCE = new MyResourceExtension();
/**
* This is my per test resource
*/
#RegisterExtension
final MyResourceExtension myResource = new MyResourceExtension();
#Test
void test() {
MY_RESOURCE.doStuff();
myResource.doStuff();
}
And here's the basic scaffolding of MyResourceExtension:
public class MyResourceExtension implements BeforeAllCallback, AfterAllCallback,
BeforeEachCallback, AfterEachCallback {
private SomeResource someResource;
private int referenceCount;
#Override
public void beforeAll(ExtensionContext context) throws Exception {
beforeEach(context);
}
#Override
public void afterAll(ExtensionContext context) throws Exception {
afterEach(context);
}
#Override
public void beforeEach(ExtensionContext context) throws Exception {
if (++referenceCount == 1) {
// Do stuff in preparation
this.someResource = ...;
}
}
#Override
public void afterEach(ExtensionContext context) throws Exception {
if (--referenceCount == 0) {
// Do stuff to clean up
this.someResource.close();
this.someResource = null;
}
}
public void doStuff() {
return this.someResource.fooBar();
}
}
You could of course wrap this all up as an abstract class and have MyResourceExtension implement just protected void before() and protected void after() or some such, if that's your thing, but I'm omitting that for brevity.

How to remove jMockit Fake/MockUp for abstract method?

Because I can't fake an abstract class directly and I know the implementing class, I added the fake to the implementing class.
#BeforeClass
public static void fakeCurrentYear() {
// Mocking the abstract 'Calender' does not work, see: https://github.com/jmockit/jmockit1/issues/71
// So we use the implementing class 'GregorianCalendar'.
new MockUp<GregorianCalendar>() {
#Mock public int get(Invocation invocation, int field) {
return 2016;
}
};
}
I'm using jMockit v 1.31 with JUnit 4.12 and Maven 3.x.
When I execute tests individually, everything is fine.
But when I execute all tests together, another test fails because the log4jlogger in the implementing class obviously uses the fake-implementation.
I think this is because previously GregorianCalendar did not overwrite that method. However, I thought the fake is automatically removed after the testclass! Is this a bug?
Can I remove it manually? I've tried stepping back to JMockit v1.25, created a static variable yearMock = new MockUp<GregorianCalendar>() ... and calling yearMock.tearDown() in a #AfterClass method, but it didn't change anything.
I've used a workaround, where I created a method in the class under test with just a single line of code
private int currentYear4digits() {
return Calendar.getInstance().get(Calendar.YEAR);
}
In my test I then mocked this method.
#BeforeClass
public static void fakeCurrentYear() {
new MockUp<MyClass>() {
#Mock
public int currentYear4digits() {
return 2016;
}
};
}
However, this is just a workaround. It would be cumbersome if the calls to Calendar where made from several classes.

Power Mockito fails to mock constructor

In order to test some legacy code, I have to use Power Mockito. Reason is that the legacy code is not using dependency injection and due to some reasons, we can't refactor the code at this time. We are running testng with ANT in our system. I have configured build.xml to use power mock and power mock testng libraries. I want to mock a constructor using Power Mockito and below is the sample code.
public class Something {
private String arg = null;
public Something() {
}
public Something(String _arg) {
arg = _arg;
}
public String doSomething() {
return arg;
}
}
public class Helper {
public Something doSomething(String arg) {
return new Something();
}
}
#PrepareEverythingForTest
class TestSC {
#Test
public void testHelper() throws Exception {
Something mockSomething = PowerMockito.mock(Something.class);
PowerMockito.whenNew(Something.class).withNoArguments().thenReturn(mockSomething);
Helper helper = new Helper();
Something test = helper.doSomething("arg");
Assert.assertEquals(test, mockSomething);
}
}
This test fails and I have no clue what is going on wrong here. Also I have seen below link to configure testng with power mockito. https://github.com/jayway/powermock/wiki/TestNG_usage
I tried extending my test class to PowerMockTestCase and it gaves me below error while running test.
[testng] [TestNG] [ERROR]
**[testng] Error creating object factory**
[testng] The tests failed.
I have below doubts in mind:-
1) Either my testng is not configured properly to use Power Mockito, but power mockito simple testcase works.
2) Some configuration is missing.
I figure out the issue lately, it was because of some dependency library i.e.javassist which was quite old. Replacing it with the newer version 3.20 resolved the issue and PowerMockito constructor mocking worked.

How to mock another method in the same class which is being tested?

I am writing JUnit Test case for a class which has two methods methodA,methodB.
I would like to mock the call to the methodB from methodA in my test case
I am using spy on the class which I am testing, but still the methodB gets executed.
here is the class
public class SomeClass
{
public Object methodA(Object object)
{
object=methodB(object);
return object;
}
public Object methodB(Object object)
{
//do somthing
return object;
}
}
here is the test class
#RunWith( org.powermock.modules.junit4.legacy.PowerMockRunner.class )
#PrepareForTest(SomeClass.class)
public class SomeClassTest {
private SomeClass var = null;
#Before
public void setUp() {
var=new SomeClass();
}
#After
public void tearDown()
{
var= null;
}
#Test
public void testMethodA_1()
throws Exception {
Object object =new Object();
SomeClass spy_var=PowerMockito.spy(var);
PowerMockito.when(spy_var.methodB(object)).thenReturn(object);
Object result = var.methodA(object);
assertNotNull(result);
}
}
The method B still gets the called though I have mocked it
PLease suggest me a solution with the proper way of mocking the methodB call from methodA of the same class.
I ran into this yesterday, for spies is best to do:
doReturn(X).when(spy).method(any())
Taking this approach will result in brittle tests which will need to change if you refactor your class under test. I would highly recommend that you try to assert your expected test results by checking state of SomeClass rather than relying on mocks.
If you do indeed need to mock MethodB then this is an indication that maybe the behaviour in MethodB actually belongs in a separate class which you could then test the interaction of SomeClass with via mocks
if you do indeed need to do what you ask for then a PartialMock is what you want.
you probably want to create a partial mock of some class but indicate that calls to MethodA should call the actual method but then mock MethodB
You can see how to use them in the Mockito documentation
As stated in their documentation though Partial mocks are a code smell, though they have identified some explicit use cases.
As per #Totoro's answer, this is just a summary here.
Annotate the object for the class you are testing with the #Spy annotation.
So this:
#Spy
#InjectMocks
MyClassUnderTest myClassUnderTest;
instead of just
#InjectMocks
MyClassUnderTest myClassUnderTest;
Use doReturn() instead of when.thenReturn() whenever asking for the mocked object from the class spyed on (class under test).
doReturn(X).when(myClassUnderTest).method(any())
I had this very same challenge. Have a look at this solution which will work for newer testing suit versions.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>2.5.0</version>
</dependency>
Solution-
//when- then for MethodA test
SomeClass spy_var=Mockito.spy(var);
doReturn(X).when(spy_var).methodB(object)
Object result = spy_var.methodA(object);
//assertions on result

Mockito mock objects returns null

I try to implement some tests for my JSF application and for the mocks I am using mockito. (I also use spring)
#RunWith(MockitoJUnitRunner.class)
public class GeneralConfigServiceImplTest {
private GeneralConfigService generalConfigService;
#Mock
private GeneralConfigDAO generalConfigDAO;
#Mock
private GeneralConfig gen;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
generalConfigService = new GeneralConfigService();
ReflectionTestUtils.setField(generalConfigService, "generalConfigDAO", generalConfigDAO);
}
#Test
public void testAddGeneralConfigCallDAOSuccess() throws DAOException, EntityNullException, IllegalEntityArgumentException, ParseException, EntityPersistException {
gen = createGeneralConfigs("label", "value");
generalConfigService.setInstance(gen);
generalConfigService.persist();
log.info(generalConfigService.getInstance().toString());
}
}
The test succeeds, but when I want to retrieve the instance with the getInstance method. All Parameters which I have set before (via the constructor before) are null.
I am new to mocked objects, so is this behavior normal, or is there a mistake in my code?
It really depends on GeneralConfigService#getInstance() implementation. Also you can simplify your test code a lot if you use #InjectMocks annotation.
When using MockitoJUnitRunner you don't need to initialize mocks and inject your dependencies manually:
#RunWith(MockitoJUnitRunner.class)
public class GeneralConfigServiceImplTest {
#InjectMocks
private GeneralConfigService generalConfigService;
#Mock
private GeneralConfigDAO generalConfigDAO;
#Test
public void testAddGeneralConfigCallDAOSuccess() {
// generalConfigService is already instantiated and populated with dependencies here
...
}
}
My problem here was the incorrect import for Test anotation:
Was
import org.junit.jupiter.api.Test;
Correct
import org.junit.Test;
Don't forget to use
MockitoAnnotations.initMocks(this);
If you are Mocking object through annotation i.e. #Mock Objectname
All method calls to Mockito mocks return null by default. If you want it to return something else you need to tell it to do so via a when statement.
It seems the you are thinking that the following will work... you call setInstance and then expect getInstance to return the value that was passed to setInstance since this is how the DAO would work. If this is what you are attempting, you shouldn't test setInstance by then calling getInstance since getInstance will return whatever you have configured the mock to return and will have no relation to what was passed to setInstance. Instead, use verify to validate that the appropriate method of the DAO was called from the setInstance method.
For example, if GeneralConfigService.setInstance calls GeneralConfigDAO.setInstance then your test should look like this...
#Test
public void testAddGeneralConfigCallDAOSuccess() throws DAOException, EntityNullException, IllegalEntityArgumentException, ParseException, EntityPersistException {
gen = createGeneralConfigs("label", "value");
generalConfigService.setInstance(gen);
generalConfigService.persist();
verify(genConfigDAO).setInstance(sameInstance(gen));
}
Also, if gen is a mock (via #Mock) why are you assigning it to something else via gen = createGeneralConfigs...
This thread is an old one, but I got the same problem with junit5 (v5.8.2) and mockito (mockito-core:jar:4.5.1) and none of the answers here helped me. After a 1.5 hours search I found this article:
https://mincong.io/2020/04/19/mockito-junit5/
which helped me! I used the first solution, so I added
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-junit-jupiter</artifactId>
<version>2.28.2</version>
<scope>test</scope>
</dependency>
as new dependency and I annotated my class with the following annotation (and I removed the #RunWith(MockitoJUnitRunner.class) annotation):
#ExtendWith(MockitoExtension.class)
Please find the explanation in the article. I hope this help to others as well!

Categories

Resources