Raghu
Raghu

Reputation: 139

How to Mock System.getProperty using Mockito

I have added mock-maker-inline text in org.mockito.plugins.MockMaker file and placed it in test/resources/mockito-extensions

In my test case I am using:

System system = mock(System.class);
when(system.getProperty("flag")).thenReturn("true");`

But I am getting the following exception:

org.mockito.exceptions.misusing.MissingMethodInvocationException: 
when() requires an argument which has to be 'a method call on a mock'.
For example:
    when(mock.getArticles()).thenReturn(articles);

Also, this error might show up because:
1. you stub either of: final/private/equals()/hashCode() methods.
   Those methods *cannot* be stubbed/verified.
   Mocking methods declared on non-public parent classes is not supported.
2. inside when() you don't call method on mock but on some other object.

Appreciate any suggestions

Upvotes: 8

Views: 35024

Answers (3)

Jose Tepedino
Jose Tepedino

Reputation: 1584

Your could also use real methods, preparing and removing the configuration before and after each test:

@Before
public void setUp() {
    System.setProperty("flag", "true");
}

@After
public void tearDown() {
    System.clearProperty("flag");
}

Upvotes: 16

glytching
glytching

Reputation: 47865

The System.getProperty() method is static, in order to mock this you'll need to use PowerMock.

Here's an example:

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;

import static org.junit.Assert.assertEquals;

@RunWith(PowerMockRunner.class)
@PrepareForTest(System.class)
public class ATest {

    @Test
    public void canMockSystemProperties() {
        PowerMockito.mockStatic(System.class);
        PowerMockito.when(System.getProperty("flag")).thenReturn("true");

        assertEquals("true", System.getProperty("flag"));
    }
}

This uses:

  • junit:junit:4.12
  • org.mockito:mocktio-core:2.7.19
  • org.powermock:powermock-api-mockito2:1.7.0
  • org.powermock:powermock-module-junit4:1.7.0

Note: @davidxxx's suggestion of avoiding the need to mock this by hiding all System access behind a facade is very sensible. Another way of avoiding the need to mock System is to actually set the desired value as a system property when running your test, System Rules offers a neat way of setting up and tearing down System property expectations in the context of Junit tests.

Upvotes: 6

davidxxx
davidxxx

Reputation: 131316

Mockito (1 as 2) doesn't provide a way to mock static methods.
So adding mockito-inline will be useless to mock the System.getProperty() method.

Generally, mocking static methods is often a bad idea as it encourages a bad design.
In your case, it is not the case as you need to mock a JDK class that you can of course not change.

So you have two ways :

  • using Powermock or any tools that allows to mock static methods

  • wrapping the System static method invocations in a class that provides instance methods, for example SystemService.

The last way is really not hard to implement and will besides provide a way to inject instance of this class where you need.
Which produces a much clearer code than a system.getProperty("flag") statement hidden between two statements.

Upvotes: 2

Related Questions