Search code examples
javamockitojunit5powermockitospring-cloud-contract

how to mock the service in controller on producer for spring cloud contract


I've been trying to mock the service inside the controller on the producer side

@Autowired
private Service service;

    @PostMapping(path = "/getone", consumes = "application/json", produces = "application/json")
public ResponseEntity<Response> getone(@RequestBody Test[] test) {
    String appId = Utils.getId();
    return new ResponseEntity<>(service.pub(test,id), HttpStatus.OK);
}

Here's how my base test class look like

@ExtendWith(SpringExtension.class)
@ActiveProfiles("test")
@SpringBootTest
@RunWith(PowerMockRunner.class)
public class ContractTest {
    
    @Autowired
    private WebApplicationContext context;

    @Mock
    private Service service;

    @BeforeEach
    void setup() {
        mockStatic(Utils.class);
        when(Utils.getId()).thenReturn("194");
       Mockito.when(service.pub(Mockito.any(Test[].class),eq("194"))).thenReturn(TestUtils.publish_success_response());
StandaloneMockMvcBuilder standaloneMockMvcBuilder = MockMvcBuilders.standaloneSetup(publishApiController, this.publishService);
RestAssuredMockMvc.standaloneSetup(standaloneMockMvcBuilder);
    }
  1. The actual service class runs here instead of the mock which is causing the issue?
    2.How do we test the failure scenarios in the @Before method ?

Solution

  • There is an important difference between @Mock and @MockBean. For your test you need @MockBean as you are replacing a Spring bean with a mock for your Spring Test Context.

    Apart from this, you are mixing JUnit 4 (@RunWith) and JUnit 5 (@ExtendWith, @BeforeEach).

    If you just want to write a test for your controller using MockMvc, you don't have to start the whole Spring Context with @SpringBootTest. Spring Boot Test provides an annotation to only start a sliced context for your MVC components: @WebMvcTest.

    For the static mock of your Utils class, you can use Mockito (since version 3.4.0) to reduce the number of additional dependencies and stick to what the Spring Boot Starter Test provides.

    A possible test can look like the following:

    // @ExtendWith(SpringExtension.class) not needed with recent Spring Boot versions
    @ActiveProfiles("test")
    @WebMvcTest
    public class ContractTest {
        
        @Autowired
        private MockMvc mockMvc;
    
        @MockBean
        private Service service;
    
        @Test
        void test() {
          
         try(MockedStatic<Utils> mockedUtils = Mockito.mockStatic(Utils.class)) {
            mockedUtils.when(Utils::getId).thenReturn("194");
    
            when(service.pub(Mockito.any(Test[].class),eq("194"))).thenReturn(TestUtils.publish_success_response());
            // ... your test
         }
          
        }
    }