Java mocking static methods

Mock static methods with Mockito

This post explains how to mock static methods. Mockito doesn’t support this behavior by default. To stub static methods, we need to enable the inline mock maker first.

Maven Dependency

For the examples, I used version 4.2.0 of Mockito.

> >org.mockito >mockito-core >4.2.0 >test  

We also need the inline mock maker to stub static methods. We can add a dependency or create a file inside the test resources to enable the new Mock maker.

Option 1: Inline mock maker dependency

Add this dependency in your pom.

> >org.mockito >mockito-inline >4.2.0 >test  

Option 2: Adding a file to enable the inline mock maker

Create a resources directory in your test directory if you do not have one already. Inside the resources create the directory mockito-extensions and in that directory the file org.mockito.plugins.MockMaker . The complete path with file should look like this: src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker .

In the file org.mockito.plugins.MockMaker paste this text mock-maker-inline , now the mock maker is available during tests.

Читайте также:  Заголовок

Mocking Static method

With MockedStatic , we can stub static methods of a class. The code uses try-with-resources to limit the scope of the stubbing to only within that try statement. The example below shows how to mock the static method Instant.now() . We first create a mock of Instant for the static method to return. Then we stub the static method and make it return the object we created earlier. Every time we call the stubbed static method we get our mocked object back.

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 
@Test void mockingStaticMethods()  try (MockedStaticInstant> mocked = mockStatic(Instant.class))  // Create a mock for the static method to return var mockInstant = mock(Instant.class); when(mockInstant.getEpochSecond()).thenReturn(1L); // Stub the static method .now() mocked.when(Instant::now).thenReturn(mockInstant); var result = Instant.now(); assertThat(result.getEpochSecond()).isEqualTo(1); > > 

Mock static method and change the default behavior

This example looks the same as the stubbing example, but now we pass an extra parameter to MockedStatic . When we pass withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS) to the mockStatic method, we call the real method for the methods we didn’t stub. By default, if we don’t supply the extra parameter, it will behave like any other mockito mock and return null when we call methods we didn’t stub. The example below shows how to stub a static method and pass other calls to the real methods.

 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 
@Test void mockingStaticMethods()  try (MockedStaticLocalDateTime> mocked = mockStatic(LocalDateTime.class, withSettings().defaultAnswer(Answers.CALLS_REAL_METHODS)))  // creating a mock for the stub to return var mockLocalDateTime = mock(LocalDateTime.class); when(mockLocalDateTime.getMinute()).thenReturn(30); // stub the static method mocked.when(LocalDateTime::now).thenReturn(mockLocalDateTime); var result = LocalDateTime.now(); assertThat(result.getMinute()).isEqualTo(30); // calling a static method that we didn't stub LocalDateTime localDateTime = LocalDateTime.of(2022, 02, 22, 19, 35, 30); // this print localDateTime = 2022-02-22T19:35:30 System.out.println("localDateTime = " + localDateTime); > > 

Conclusion

In this post, we enabled the inline mock maker to mock static methods. We also saw two examples of how to create a MockedStatic object and change its default behavior.

If you are curious and want to know more about what you can do with Mockito, please check out their documentation https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html. It lists all the Mockito features and how to use them.

Further reading

More about testing in Java:

Источник

Mock Static Methods with Mockito

Learn to mock the static methods using Mockito in unit testing in Java. Previously, we had to use PowerMock to mock private and static methods, but starting version 3.4.0, Mockito supports mocking static methods directly. Read getting started with Mockito guide for setup instructions.

To mock static methods, we need to use the inline mock-making facility provided by mockito-inline module. Note that this module is separate from mockito-core module for some time, and in a future release it will be merged with mockito-core itself.

The mockito-inline module has been developed separately for community feedback and provides the mocking capability for static methods; and final classes and methods which previously were considered unmockable. It uses a combination of both Java instrumentation API and sub-classing rather than creating a new class to represent a mock.

 org.mockito mockito-inline 4.6.1 test 

For demo purposes, we are creating a simple class with two methods.

  • The first method does not take any argument and returns the string value “foo”.
  • The second method takes a variable number of int arguments and returns their sum.
class ClassWithStaticMethod < public static String getVal() < return "foo"; >public static int add(int. args) < return IntStream.of(args).sum(); >>

The MockedStatic represents an active and scoped mock of a type’s static methods. Due to the defined scope of the static mock, it returns to its original behavior once the scope is released. To define mock behavior and to verify static method invocations, use the MockedStatic reference returned from the Mockito.mockStatic() method.

It is necessary to call ScopedMock.close() method to release the static mock once it has been used and is no longer needed. It is therefore recommended to create this object within a try-with-resources statement unless when managed explicitly.

The following is the syntax to use the MockedStatic class in a unit test.

try (MockedStatic mock = mockStatic(AppStatic.class)) < //record mock expectations //test code //verify mock >

If we do not use try-with-resources block, as suggested, the mocking/stubbing/verifying will work as expected but leaves the class in a mocked state.

3. Mocking No-Args Static Methods

Let us mock the first method getVal() that takes no arguments and returns a String value «foo» . We are mocking the getVal() method and returning the value «bar» from the mock.

When we invoke the getVal() method, outside the mock scope, we should the value as “bar” and inside the scope, we should get the value “foo”.

@Test public void testGetVal() < //Outside scope assertEquals("foo", ClassWithStaticMethod.getVal()); try (MockedStatic mockStatic = mockStatic(ClassWithStaticMethod.class)) < mockStatic.when(ClassWithStaticMethod::getVal).thenReturn("bar"); //Inside scope assertEquals("bar", ClassWithStaticMethod.getVal()); mockStatic.verify(ClassWithStaticMethod::getVal); >//Outside scope assertEquals("foo", ClassWithStaticMethod.getVal()); >

4. Mocking a Static Method with Arguments

Mocking the static methods that accept arguments and return values is pretty much same as the previous section. Additionally, we can use flexible argument-matchers in expectations.

Note that we are using the lambda expression syntax for invoking the static method.

@Test public void testAdd() < assertEquals(3, ClassWithStaticMethod.add(1, 2)); try (MockedStatic mockStatic = mockStatic(ClassWithStaticMethod.class)) < mockStatic.when(() ->ClassWithStaticMethod.add(anyInt(), anyInt())).thenReturn(10); assertEquals(10, ClassWithStaticMethod.add(1, 2)); mockStatic.verify(() -> ClassWithStaticMethod.add(1, 2)); > assertEquals(3, ClassWithStaticMethod.add(1, 2)); >

In this tutorial, we learned to create, record expectations and verify the mocks have static methods. Make sure you understand the fact that a static mock is expected to be used in a defined scope, and the module mockito-inline can be merged with mockito-core in the future.

Источник

How to mock static methods with Mockito

This article will be covering mocking static methods with Mockito. We will try to answer the question is this even possible to do it and why should we ever mock anything that is static.

2. Static methods

Let’s start with a simple definition. Static methods are that methods in Java that can be called without creating an instance of the class. A static method belongs to the class rather than the object of a class.

Using static methods in Java is sometimes necessary, however, most developers limit their use to pure functions which are independent (not using external dependencies). Whether we like them or not, we do sometimes have to rely on them and also mock them in unit tests.

3. Mocking static method with Mockito 3.x

The good news is that from the latest Mockito version mocking static methods is finally supported.

To make this possible, a single dependency had to be added to the pom.xml file:

 org.mockito mockito-inline 3.6.28 test  

The latest version of Mockito inline dependency should be found in our Maven Repository.

If you are using mockito-core you will need to replace it with mockito-inline dependency otherwise you will face the following exception:

org.mockito.exceptions.base.MockitoException: The used MockMaker SubclassByteBuddyMockMaker does not support the creation of static mocks Mockito's inline mock maker supports static mocks based on the Instrumentation API. You can simply enable this mock mode, by placing the 'mockito-inline' artifact where you are currently using 'mockito-core'. Note that Mockito's inline mock maker is not supported on Android. 

3.1. Simple class with a static method use for testing

Let’s consider we have a simple class WelcomeUtil with a single static method generateWelcome(. ) that we want to mock in the JUnit test:

package com.frontbackend.libraries.mockito; public final class WelcomeUtil < public static String generateWelcome(String name) < return String.format("Welcome %s", name); >private WelcomeUtil() < >> 

3.2. Mockito test class

The test code of this class could looks as follows:

package com.frontbackend.libraries.mockito; import static org.junit.Assert.assertEquals; import org.junit.Test; import org.mockito.MockedStatic; import org.mockito.Mockito; public class MockitoStaticMethodTest < @Test public void testMockStaticMethods() < assertEquals("Welcome John", WelcomeUtil.generateWelcome("John")); try (MockedStatictheMock = Mockito.mockStatic(WelcomeUtil.class)) < theMock.when(() ->WelcomeUtil.generateWelcome("John")) .thenReturn("Guten Tag John"); assertEquals("Guten Tag John", WelcomeUtil.generateWelcome("John")); > assertEquals("Welcome John", WelcomeUtil.generateWelcome("John")); > > 

There are some things we need to explain here:

  • note that mocked static method will be only visible in the try-with-resources block,
  • so different test cases should be tested in different try blocks,
  • static methods could be mocked only using an inline way,
  • after try-with-resource block behavior of the static method will be as originally implemented.

4. Mocking static method with Mockito in older versions 2.x

Now, what about the older version of the Mockito framework? does it support mocking static methods?. The answer is unfortunately NO.

But we could use another library such as PowerMock to mock the static method without using the latest version of Mockito.

First, let’s start with adding necessary dependencies to our pom.xml file:

   libraries com.frontbackend.libraries 1.0-SNAPSHOT  4.0.0 powermock  org.mockito mockito-core 2.23.4 test  org.powermock powermock-core 2.0.9 test  org.powermock powermock-api-mockito2 2.0.9 test  org.powermock powermock-module-junit4 2.0.9 test    

The list of dependencies we used (you can check the latest versions in links below):

4.1. PowerMock test class

The PowerMock uses internally Mockito API so we still need the Mockito library in our dependencies.

The following shows how to create a test that mocks the static WelcomeUtil.generateWelcome(. ) method just like in the above example:

package com.frontbackend.libraries.powermock; import static org.junit.Assert.assertEquals; import static org.powermock.api.mockito.PowerMockito.mockStatic; import static org.powermock.api.mockito.PowerMockito.when; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import com.frontbackend.libraries.powermock.utils.WelcomeUtil; @RunWith(PowerMockRunner.class) @PrepareForTest(WelcomeUtil.class) public class PowermockStaticMethodTest < @Test public void shouldMockStaticMethodTest() < final String value = "Guten Tag John"; mockStatic(WelcomeUtil.class); when(WelcomeUtil.generateWelcome("John")).thenReturn(value); assertEquals("Guten Tag John", WelcomeUtil.generateWelcome("John")); >> 

In this example mockStatic(. ) and when(. ) methods comes from PowerMockito library.

5. Mocking static method with Mockito 4.x

What about Mockito in version 4.x? The same as for 3.x, you will still need the mockito-inline library to mock static methods otherwise the system will throw a MockitoException . The good news is that we don’t have to declare mockito-core separately because mockito-inline uses mockito-core as dependency.

   libraries com.frontbackend.libraries 1.0-SNAPSHOT  4.0.0 mockito-static-v4  org.mockito mockito-inline 4.5.1 test    

6. Conclusion

In this article, we presented how to mock static methods with Mockito and PowerMockito libraries. When it is not about mocking methods from third-party libraries, consider refactoring the code so that mocking a static method wouldn’t be necessary. It is always not the best solution.

Test examples used in this article, are available in the GitHub Repository:

Источник

Оцените статью