Search code examples
javaspring-bootmockitojunit4

Mock RestTemplate in SubSubclass


there's a problem here!

In my application I have a Consumer (kafka) that uses a Facade that uses a Client that calls a rest Api with RestTemplate

I want (have) to test the whole flow excluded the rest call. so I've tried to mock RestTemplate but without success -_-

here an example of my classes

@Service
public class KafkaConsumer{
    @Autowired MyFacade facade;

    @KafkaListener
    public void onMessage(){
        facade.awesomeMethod();
    }
}


@Service
public class MyFacade{
    @Autowired MyClient client;
   
    public void awesomeMethod(){
        client.callApi();
    }
}

@Service
public class MyClient{
    @Autowired RestTemplate restTemplate;

    public void callApi(){
        restTemplate.exchange(.....);
    }
}

now I'm tring to build a test with mock but something goes wrong and RestTemplate call real server

here test class

@ActiveProfile("test")
@RunWith(SpringRunner.class)
@SpringbootTest
@EmbeddedKafka
public class MyFailTest{

    @Mock RestTemplate restTemplate;
    @InjectMocks MyFacade facade;
    @InjectMocks MyClient client;
    @InjectMocks KafkaConsumer consumer;
    @Autowired KafkaProducer producer;

    @Test
    public void test(){

        Mokito.when(restTemplate.exchange(....)).thenReturn(new ResponseEntity<Void>(HttpStatus.OK);)

        producer.send("My Kafka Message");
    }
}

here my test dependecies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.kafka</groupId>
        <artifactId>spring-kafka-test</artifactId>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-core</artifactId>
        <version>3.11.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-engine</artifactId>
        <version>5.4.0</version>
        <scope>test</scope>
    </dependency>

Junit4 and Springboot 2.6.7

I think I'm failing in @Mock and @InjecMock logic, i've tried some combination of them ; ) but without success


Solution

  • thanks to @geobreze comment I drilled down into @MockBean. It was a way tried on my thousands tries but I copied some code without really understand what it was coping

    At the end I've used @SpyBean because @MockBean mocks all methods class. To semplify implementation I've mocked Client object, exchenge of RestTemplate it is a little bit complex, I didn't want fall in other stupid error.

    It is not useful declare all classes chain, so I've removed facade and I've used @autowired annotation rather than @InjectMock

    here my test

    @ActiveProfile("test")
    @RunWith(SpringRunner.class)
    @SpringbootTest
    @EmbeddedKafka
    public class MySuccessfullTest{
    
        @SpyBean MyClient client;
        @Autowired KafkaConsumer consumer;
        @Autowired KafkaProducer producer;
    
        @Test
        public void test(){
            MyClientResponse responseObject = MyClientResponse();
    
            Mokito.doReturn(responseObject).when(client).callApi();
            producer.send("My Kafka Message");
        }
    }