<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Mohammad Javed</title>
    <description>The latest articles on Forem by Mohammad Javed (@jmohammadmirza).</description>
    <link>https://forem.com/jmohammadmirza</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1125730%2Ff687ad53-c004-4f5f-9a83-ddc1e8e5699a.jpeg</url>
      <title>Forem: Mohammad Javed</title>
      <link>https://forem.com/jmohammadmirza</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/jmohammadmirza"/>
    <language>en</language>
    <item>
      <title>Spring Boot Integration Testing</title>
      <dc:creator>Mohammad Javed</dc:creator>
      <pubDate>Thu, 15 May 2025 16:28:17 +0000</pubDate>
      <link>https://forem.com/jmohammadmirza/spring-boot-integration-testing-bp6</link>
      <guid>https://forem.com/jmohammadmirza/spring-boot-integration-testing-bp6</guid>
      <description>&lt;h2&gt;
  
  
  Spring Boot Integration Testing
&lt;/h2&gt;

&lt;p&gt;You have mastered Junit. You are Mockito maestro.But if you are not using Spring’s Integration Testing Tools, you are only fighting half the battle.&lt;/p&gt;

&lt;p&gt;Let us dive into the world of Spring Integration Testing- where real applications meet real tests.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lonely World of Unit tests
&lt;/h2&gt;

&lt;p&gt;For many Java developers, testing begins and ends with JUnit and Mockito. These tools are fantastic for isolating components and verifying behaviour in a controlled environment. But they are like testing a car’s engine on a workbench- it might run perfectly there, but what happens when you put it in the chassis and take it for a spin ?&lt;/p&gt;

&lt;p&gt;That’s where Spring’s integration testing framework comes into play.&lt;/p&gt;

&lt;p&gt;While you’ve been meticulously mocking every dependency, Spring has been quietly offering tools to test your application as a cohesive whole.&lt;/p&gt;

&lt;h2&gt;
  
  
  Spring Mock MVC: Your Application’s Mirror
&lt;/h2&gt;

&lt;p&gt;Spring MockMvc allows you to test your controllers without deploying to a server, yet still exercise the full Spring MVC lifecycle. It’s like having a mini-version of your application running in a test bubble.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Autowired
private MockMvc mockMvc;
@Test
public void testGetUsers() throws Exception {
mockMvc.perform(get("/api/users"))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].name").value("John Doe"));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No more “it works on my machine” — with MockMvc, you’re testing the actual HTTP layer, response status codes, headers, and content.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;@WebMvcTest&lt;/code&gt;vs &lt;code&gt;@SpringBootTest&lt;/code&gt;: Choose Your Fighter
&lt;/h2&gt;

&lt;p&gt;“Do I need both @WebMvcTest and @SpringBootTest?” I hear you ask. Let’s clear up the confusion:&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;@WebMvcTest&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@WebMvcTest(UserController.class)
public class UserControllerTest {
// Your test code here
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This annotation is focused on testing the web layer only. It:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disables full auto-configuration&lt;/li&gt;
&lt;li&gt;Only configures components relevant to MVC tests&lt;/li&gt;
&lt;li&gt;Scans only the specified controller&lt;/li&gt;
&lt;li&gt;Automatically configures MockMvc&lt;/li&gt;
&lt;li&gt;Think of&lt;code&gt;@WebMvcTest&lt;/code&gt; as a lightweight champion — fast, nimble, and focused on a single task.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;@SpringBootTest&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootTest
public class ApplicationIntegrationTest {
// Your test code here
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the heavyweight champion that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates a full application context&lt;/li&gt;
&lt;li&gt;Loads the entire Spring application&lt;/li&gt;
&lt;li&gt;Can test interaction between all beans&lt;/li&gt;
&lt;li&gt;Provides a realistic testing environment&lt;/li&gt;
&lt;li&gt;So do you need both? &lt;strong&gt;No,&lt;/strong&gt; Use either of them and not both in same Test class&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;@Import&lt;/code&gt; and &lt;code&gt;@ContextConfiguration&lt;/code&gt;: The Context Jugglers
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Import
@WebMvcTest
@Import({SecurityConfig.class, CustomMapper.class})
public class ControllerTest {
// Your test code here
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Think of &lt;code&gt;@Import&lt;/code&gt; as your VIP guest list. It tells Spring, “Hey, I know we’re only testing the web layer, but I really need these specific beans at the party.” Use it when you need to supplement your test slice with additional components.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;code&gt;@ContextConfiguration&lt;/code&gt;
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@SpringBootTest
@ContextConfiguration(classes = {TestConfig.class})
public class CustomIntegrationTest {
// Your test code here
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;@ContextConfiguration&lt;/code&gt; is more like rebuilding the venue according to your specifications. It gives you explicit control over how the application context is built, allowing you to specify configuration classes, XML configurations, or even context initializers.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;@ContextConfiguration&lt;/code&gt; when you need deeper control over your test environment setup.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Integration Tests Go Wrong: Common Issues and Solutions
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;The error: &lt;code&gt;java.lang.IllegalStateException: Unable to find a @SpringBootConfiguration by searching packages upwards from the test.&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So, if have the main configuration (class having &lt;code&gt;@SpringBootApplication&lt;/code&gt;) is under &lt;code&gt;src/main/java/com/develop&lt;/code&gt; then Integration Test should be under &lt;br&gt;
&lt;code&gt;src/test/java/com/develop&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Spring Boot's test framework tries to find the main configuration class by searching upwards from the test class's package, but since your test is in the default package, it can't find.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;@MockBean&lt;/code&gt; gives compiler warning as below &lt;code&gt;'org.springframework.boot.test.mock.mockito.MockBean'&lt;/code&gt; is deprecated since version &lt;code&gt;3.4.0&lt;/code&gt; and marked for removal&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Assume below is the Integration Test&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@WebMvcTest(JobController.class)
@Import(JobControllerITTest.TestConfig.class)
public class JobControllerITTest {
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then Mock the service class as below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; @Configuration
    static class TestConfig {
        @Bean
        public JobService jobService() {
            // Create and return a mock JobService
            return org.mockito.Mockito.mock(JobService.class);
        }
    }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;Exception encountered during context initialization - cancelling refresh attempt: &lt;code&gt;org.springframework.beans.factory.UnsatisfiedDependencyException&lt;/code&gt;: Error creating bean with name 'jobService': Unsatisfied dependency expressed through field 'auditRepository': No qualifying bean of type &lt;code&gt;'com.develop.AuditRepository'&lt;/code&gt;available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: &lt;code&gt;{@org.springframework.beans.factory.annotation.Autowired(required=true)}&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Mock  all the Repo which are used by Service class to avoid as shown below in the code.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Configuration
    static class TestConfig {
        @Bean
        public JobService jobService() {
            return Mockito.mock(JobService.class);
        }

        @Bean
        public AuditRepository auditRepository() {
            return Mockito.mock(AuditRepository.class);
        }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;See below for complete code example&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Code Example
&lt;/h2&gt;

&lt;p&gt;Assuming basic controller like below with JobService calling a Mongo Repo- like &lt;code&gt;AuditRepository&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@RestController
public class JobController {

    @Autowired
    JobService jobService;

    @GetMapping("/api/jobs")
     public List&amp;lt;Job&amp;gt; getAllJobs(@RequestParam String query,HttpServletRequest request) {

       return jobService.findByTitleLike(query);

     }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;//Domain&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@Data
@NoArgsConstructor
@AllArgsConstructor
public class Job {
    private Long id;
    private String title;
    private String description;
    private String location;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We have below working and compiled Integration Tests in (IntelliJ IDE)&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;

@WebMvcTest(JobController.class)
@Import(JobControllerITTest.TestConfig.class)
public class JobControllerITTest {

    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private JobService jobService;


    private List&amp;lt;Job&amp;gt; mockJobs;

    @Configuration
    static class TestConfig {
        @Bean
        public JobService jobService() {
            return Mockito.mock(JobService.class);
        }

        @Bean
        public AuditRepository auditRepository() {
            return Mockito.mock(AuditRepository.class);
        }

        @Bean
        public JobRepository jobRepository() {
            return Mockito.mock(JobRepository.class);
        }

      /** Add all the Repo which are used by Service class to avoid 

Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'Service': Unsatisfied dependency expressed through field 'auditRepository': No qualifying bean of type 'com.develop.AuditRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}


*/

    }


    @BeforeEach
    public void setup() {
        // Create some mock jobs for testing
        mockJobs = Arrays.asList(
                createJob("1", "Java Developer", "Senior Java Developer position", "Remote"),
                createJob("2", "Java Architect", "Experienced Java Architect needed", "New York")
        );
        // Configure mock behavior
        when(jobService.fetchAll()).thenReturn(mockJobs);
        when(jobService.findByTitleLike(Mockito.anyString())).thenReturn(mockJobs);

    }

    private Job createJob(String id, String title, String description, String location) {
        Job job = new Job();
        job.setId(id);
        job.setTitle(title);
        job.setDescription(description);
        job.setLocation(location);
        return job;
    }

    @Test
    public void testGetAllJobs_Success() throws Exception {
        // Given: The service returns jobs when searching for "Java"
        when(jobService.findByTitleLike("Java")).thenReturn(mockJobs);

        // When &amp;amp; Then: We call the API and verify the response
        mockMvc.perform(get("/api/jobs")
                        .param("query", "Java")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(jsonPath("$[0].title").value("Java Developer"))
                .andExpect(jsonPath("$[1].title").value("Java Architect"))
                .andExpect(jsonPath("$").isArray())
                .andExpect(jsonPath("$.length()").value(2));
    }

    @Test
    public void testGetAllJobs_EmptyResults() throws Exception {
        // Given: The service returns empty list when searching for "Python"
        when(jobService.findByTitleLike("Python")).thenReturn(Arrays.asList());

        // When &amp;amp; Then: We call the API and verify we get an empty array
        mockMvc.perform(get("/api/jobs")
                        .param("query", "Python")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(content().contentType(MediaType.APPLICATION_JSON))
                .andExpect(jsonPath("$").isArray())
                .andExpect(jsonPath("$.length()").value(0));
    }

    @Test
    public void testGetAllJobs_MissingQueryParam() throws Exception {
        // When &amp;amp; Then: We call the API without the required query parameter
        mockMvc.perform(get("/api/jobs")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isBadRequest());
    }

    @Test
    public void testGetAllJobs_ServiceException() throws Exception {
        // Given: The service throws an exception when searching for "Error"
        when(jobService.findByTitleLike("Error")).thenThrow(new RuntimeException("Service error"));

        // When &amp;amp; Then: We call the API and verify we get a server error
        mockMvc.perform(get("/api/jobs")
                        .param("query", "Error")
                        .contentType(MediaType.APPLICATION_JSON))
                .andExpect(status().isInternalServerError());
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For More content on Spring Boot Read &lt;a href="https://medium.com/@javedmj786/migrating-to-spring-boot-3-5-performance-enhancements-in-microservices-557fe73bbffa" rel="noopener noreferrer"&gt;here&lt;/a&gt;. &lt;/p&gt;

</description>
      <category>springboot</category>
      <category>testing</category>
      <category>mockmvc</category>
      <category>java</category>
    </item>
  </channel>
</rss>
