Class JUnitSpringBootAdminIntegrationSetup

java.lang.Object
org.broadleafcommerce.test.junit.JUnitSpringBootAdminIntegrationSetup

@ExtendWith(org.springframework.test.context.junit.jupiter.SpringExtension.class) @SpringBootTest(classes=AdminApplication.class) @TestPropertySource(locations="classpath:/config/bc/overrideprops/admin_springboot_testoverrides.properties") @Import(AdminSpringBootTestConfiguration.class) public abstract class JUnitSpringBootAdminIntegrationSetup extends Object
This is a convenient base class for launching a spring boot test against the admin application. The primary testing technologies employed here are JUnit and Spring's MockMVC. This integration test focuses on testing the controller API. It has the following beneficial attributes:
  • The test is much less brittle than a traditional presentation-tier functional test, but with nearly the same full lifecycle coverage benefits.
  • Development iteration and test execution times are less.
  • This test will generally survive a admin pipeline refactor without much change. It has good longevity characteristics.
  • Raw database confirmation of operations is trivial.
Notably, the spring boot instance launched does not include a embedded container, but does include a full HSQL database. The database is fully network ready and can be queried by an external sql tool while the test is running.

Tests should extend JUnitSpringBootAdminIntegrationSetup and employ standard MockMVC test calls to simulate admin controller interactions. The AdminTestHelper is included for convenience API around starting an Entity-Manager-In-View session for retrieving and verifying records from the database. This is useful when directly confirming data results from admin MockMVC calls.

JUnitSpringBootAdminIntegrationSetup already introduces the most likely filters and user request roles required for admin interaction. Extending tests can customize by overriding getOrderedFilters(Filter...) and getRequestRoles(String...). Note, this is different than the usage of @WithMockUser, which should be annotated on your test methods and specify the admin user name to associate with the test.

If you have existing, non-spring-boot tests already running, you'll want to separate the execution of your spring boot tests. Otherwise, you'll likely run into problems during test app context initialization in regard to some classloader nuances and static variables. This can be achieved by creating multiple <execution> elements in your maven-surefire-plugin configuration in your pom.xml. Review the documentation for the maven plugin on how to include and exclude tests into separate executions. http://maven.apache.org/surefire/maven-surefire-plugin/examples/inclusion-exclusion.html

Several libraries are required to be on the test classpath in order to get admin spring boot testing. You can include the following in your pom.xml <dependencies> section.
     <dependency>
        <groupId>org.broadleafcommerce</groupId>
        <artifactId>integration</artifactId>
        <version>${blc.version}</version>
        <classifier>tests</classifier>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.broadleafcommerce</groupId>
        <artifactId>integration</artifactId>
        <version>${blc.version}</version>
        <scope>test</scope>
    </dependency>
   <dependency>
        <groupId>org.broadleafcommerce</groupId>
        <artifactId>broadleaf-thymeleaf3-presentation</artifactId>
        <version>${broadleaf-presentation.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.security</groupId>
        <artifactId>spring-security-test</artifactId>
        <version>${spring.security.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <version>${spring.boot.test.version}</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>com.broadleafcommerce</groupId>
        <artifactId>broadleaf-boot-starter-hsql-database</artifactId>
        <version>${database.starter.version}</version>
        <scope>test</scope>
    </dependency>
 

An example test will look something like this:
   public class MyIT extends JUnitSpringBootAdminIntegrationSetup {

        protected AdminTestHelper h;

        @Override
        public void setUp() throws Exception {
            super.setUp();
            h = getHelper(AdminTestHelper.class);
        }

        @Test
        @WithMockUser(username = "admin")
        public void testProductAdd() throws Throwable {
            MvcResult result = getMockMvc().perform(post("/admin/product/new/enterprise-add").contextPath("/admin").accept("text/html")
                    .param("entityType", ProductImpl.class.getName())
                    .header("host", "global.local.com"))
                    .andReturn();
            String redirectUrl = result.getResponse().getRedirectedUrl();
            Assert.assertTrue(redirectUrl.startsWith("/admin/product"));
            Long id = Long.parseLong(redirectUrl.substring(redirectUrl.lastIndexOf("/") + 1, redirectUrl.indexOf("?")));
            result = getMockMvc().perform(post("/admin/product/" + id).contextPath("/admin").accept("text/html")
                    .param("isPostAdd", "true")
                    .param("entityType", ProductImpl.class.getName())
                    .param("ceilingEntityClassname", Product.class.getName())
                    .param("id", String.valueOf(id))
                    .param("sectionCrumbs", ProductImpl.class.getName() + "--" + id)
                    .param("fields['defaultSku.name'].value", "Vendor Product")
                    .param("fields['defaultSku.retailPrice'].value", "12")
                    .param("fields['defaultCategory'].value", "3002")
                    .param("fields['url'].value", "/hot-sauces/thing")
                    .header("host", "global.local.com"))
                    .andReturn();
            Assert.assertEquals(result.getResponse().getStatus(), HttpServletResponse.SC_FOUND);
        }
   }
 

Finally, a warning. When the spring-boot-starter-test dependency is on the classpath, MockitoPostProcessor is automatically included, which causes class scanning while looking for @Configuration classes. This ends up loading some domain classes in the classloader at startup that interferes with normal Load Time Weaving operations in Broadleaf. As a result, AdminSpringBootTestConfiguration automatically configures a no-op implementation of MockitoPostProcessor to avoid the scanning, at the cost of removing Mockito support in the Spring Boot test.
Author:
Jeff Fischer
  • Constructor Details

    • JUnitSpringBootAdminIntegrationSetup

      public JUnitSpringBootAdminIntegrationSetup()
  • Method Details

    • setUp

      @BeforeEach public void setUp() throws Exception
      Throws:
      Exception
    • getMockMvc

      public org.springframework.test.web.servlet.MockMvc getMockMvc()
    • getHelper

      public <T extends AdminTestHelper> T getHelper(Class<T> helperType)
    • getOrderedFilters

      protected jakarta.servlet.Filter[] getOrderedFilters(jakarta.servlet.Filter... basicFilters)
      Override to add filters and change ordering
      Parameters:
      basicFilters -
      Returns:
    • getRequestRoles

      protected String[] getRequestRoles(String... basicRoles)
      Override to add or change roles. These roles are important for anywhere in an admin flow where the HttpServletRequest#isUserInRole API is used.
      Parameters:
      basicRoles -
      Returns: