Search code examples
javajunit5spring-boot-test

How to test when Superclass method is called?


I tried to test below class but got "org.mockito.exceptions.base.MockitoException: Only void methods can doNothing()!" and when i tried for Mocking i got nullpointerException.

@Configuration

@Profile("cloud")
public class PsqlConfiguration extends AbstractCloudConfig {

    @Bean
    public DataSource dataSource() {
        return connectionFactory().dataSource();
    }
}

Test written =>

@RunWith(MockitoJUnitRunner.class)
class PsqlConfiguration extends AbstractCloudConfig{

    @Test
    void dataSource() {
        PsqlConfiguration ch = Mockito.spy(new PsqlConfiguration());
        Mockito.doNothing().when((AbstractCloudConfig)ch).connectionFactory();
        ch.dataSource();
    }

Mock Test Written

@RunWith(MockitoJUnitRunner.class)

class PsqlConfigurationTest {

@InjectMocks
PsqlConfiguration psqlConfiguration = new PsqlConfiguration();

AbstractCloudConfig config = Mockito.mock(AbstractCloudConfig.class);

@Test
void dataSource() {
    DataSource dataSource = Mockito.mock(DataSource.class);
    Cloud cloud = Mockito.mock(Cloud.class);
    ServiceConnectionFactory factory = new CloudServiceConnectionFactory(cloud);
    Mockito.when(config.connectionFactory()).thenReturn(factory);
    System.out.println(config.connectionFactory());
    Mockito.when(config.connectionFactory().dataSource()).thenReturn(dataSource);
    assertNull(psqlConfiguration.dataSource()); // This gives null

}

}


Solution

  • Judging from your test, I imagine you want to verify() that your configuration's dataSource() method is being called. If so, you probably want something like the following:

    @Test
    void dataSource() {
        PsqlConfiguration ch = Mockito.spy(new PsqlConfiguration());
        DataSource mockDs = Mockito.mock(DataSource.class);
        Mockito.doReturn(mockDs).when(ch).dataSource();
    }
    

    The reason you are getting the error is that the AbstractCloudConfig class's dataSource() method returns a DataSource, not void. You can only use doNothing() to mock void methods.

    If you really want to mock the superclass, you could do something like this:

    @Test
    void dataSource() {
        PsqlConfiguration ch = Mockito.spy(new PsqlConfiguration());
        DataSource mockDs = Mockito.mock(DataSource.class);
        ConnectionFactory mockFactory = Mockito.mock(ConnectionFactory.class);
        Mockito.doReturn(mockDs).when(ch).dataSource();
        Mockito.doReturn(mockFactory).when((AbstractCloudConfig)ch).connectionFactory();
        ch.dataSource();
        verify(ch).connectionFactory();
    }
    

    Note however, that this test is meaningless as it is written. Your configuration class does not execute any code that is not from your framework (as far as you have written, and the configuration is loaded by Spring). Tests should only test your own code, not the underlying framework (which has its own tests).


    I see by your comment:

    If i directly mock child class method then it works but code coverage is 0 percent so i thought to mock " connectionFactory().dataSource()" . So that it gives 100 percent code coverage, But it gives NullPointerException

    That you're simply doing this for code coverage. This is not really a good practice, as:

    1. You are bloating the code base to write tests for something that is not within your code's responsibility.
    2. 100% coverage does not mean that the code base is bug-free.

    Now, if your configuration source also did something with the dataSource (aside from just retrieving it), you might write a test for that to assert that everything in your code uses it correctly. However, as written, it does not really help in any way.