简体   繁体   中英

Mock a class initialised by a static method

I have the following class which has an object 'client' which is initialized by a static method. I do not want to use Powermock and let it get initialized by this static method. I am looking to use mockito to mock the this call => client.rxQueryWithParams().

Is this possible? Tried with the mock up as follows but I still enter the client.rxQueryWithParams() call thus the mockup is not taking effect.

This would have mocked fine it I had just Autowired the SQLClient instead in a framework like Spring. Unable to achieve this in a normal class as follows. If relevant, I am ok to mock that PostgreSQLClient.createShared() call but it doesn't seem to be achievable via mockito and not looking to introduce Powermock as mentioned. Is there a way around this? Thanks.

public class MainClass{
    private final SQLClient client;

    public MainClass(Vertx vertx, JsonObject config) {
        client = PostgreSQLClient.createShared(vertx, getData(config));
    }

    Single<ResultSet> insert(AddEventRequest request) {
        // some logic 
        return client.rxQueryWithParams(query, new JsonArray(params)); // I want to mock out this call. 
    }
}

Test

@ExtendWith(MockitoExtension.class)
public class MainClassTest {

    private TestSubscriber<Response> subscriber;
    private JsonObject configuration;
    private MainClass event;

    @Mock
    private SQLClient client;

    @BeforeEach
    public void init() {
        configuration = SomeStaticMethod.load();
        event = new MainClass(Vertx.vertx(), configuration);
        subscriber = new TestSubscriber<>();
    }

    @Test
    public void test() {
        Request request = getRequest(); // just a method creating an object with some values
        
        // this mock doesn't have any effect
        when(client.rxQueryWithParams(anyString(), any(JsonArray.class))).thenThrow(new RuntimeException());

        event.addEvent(request).subscribe(subscriber);
        subscriber.assertCompleted();
        subscriber.assertNoErrors();
    }
}

It is impossible without PowerMock or similar tool.

Mocking static methods is available since Mockito 3.4.

See pull request: Mockito #1013: Defines and implements API for static mocking.

Please note that the fact that this feature is available is not equivalent with recommendation to use it. It is aimed at legacy apps where you cannot refactor the source code.

You will be better off refactoring your MainClass to accept an SQLClient argument in a constructor. You can add an additional, delegating constructor if you need to minimize the impact on your code.

Having said that:

try (MockedStatic<PostgreSQLClient> postgreSQLClientStatic = Mockito.mockStatic(PostgreSQLClient.class)) {
    postgreSQLClientStatic.when(() -> PostgreSQLClient.createShared(any(), any())).thenReturn(client);
    // NOTE: I create the event when mocked PostgreSQLClient is in scope
    MainClass event = new MainClass(Vertx.vertx(), configuration);
    when(client.rxQueryWithParams(anyString(), any()))
        .thenThrow(new RuntimeException("exception from mock"));
    event.insert(request);
}

You can inject the mock instance into MainClass instance via ReflectionTestUtils packaged under org.springframework.test.util

  ReflectionTestUtils.setField(event , "client", client);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM