Showing posts with label Test. Show all posts
Showing posts with label Test. Show all posts

Tuesday, 8 January 2013

Spring Selenium Tests With Annotations

This post describes how to implement Selenium tests in Java. It is inspired from the post by Alex Collins, with annotations. The code is available on GitHub in the Spring-Selenium-Test directory. Some alternative and much lighter techniques are available to unit test a Spring MVC application. To unit test services, see here.

Page, Configuration & Controller

We create a simple page with 'Hello World':
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Welcome !!!</title>
</head>
<body>
  <h1>
   Hello World !
  </h1>
</body>
</html>
We keep our controller very simple:
@EnableWebMvc
@Configuration
@ComponentScan(basePackages = "com.jverstry")
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean
    public ViewResolver getViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("WEB-INF/pages/");
        resolver.setSuffix(".jsp");
        return resolver;
    }

}
and our controller too:
@Controller
public class MyController {

    @RequestMapping(value = "/")
    public String home() {
        return "index";
    }

}

For Selenium Testing

We create a configuration for testing. It provides the URL to open the application locally. The application is opened with Firefox:
@Configuration
public class TestConfig {

    @Bean
    public URI getSiteBase() throws URISyntaxException {
        return new URI("http://localhost:10001/spring-selenium-test-1.0.0");
    }

    @Bean(destroyMethod="quit")
    public FirefoxDriver getDrv() {
        return new FirefoxDriver();
    }

}
We also define an abstract class as a basis for all tests. It automatically closes Firefox after the test:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ TestConfig.class })
public abstract class AbstractTestIT {

    @Autowired
    protected URI siteBase;

    @Autowired
    protected WebDriver drv;

    {
        Runtime.getRuntime().addShutdownHook(new Thread() {
           @Override
           public void run() {
                drv.close();
           }
        });
    }

}
And we implement a selenium test where we make sure our page contains 'Hello World':
public class SeleniumTestIT extends AbstractTestIT {

    @Test
    public void testWeSeeHelloWorld() {
        drv.get(siteBase.toString());
        assertTrue(drv.getPageSource().contains("Hello World"));
    }

}
The maven dependencies are the same as those described in Alex Collins's post.

Building The Application

If you build the application, it will open and close firefox automatically. The test will be successful.

Thursday, 6 September 2012

Spring MVC Controller JUnit Testing

JUnit testing Spring MVC controllers is not an easy task. But recently, a new project (now included in Spring 3.2) offers new tools to facilitate this. This post illustrates how to test a simple controller via JUnit tests.

This code is a variation of the code used in JUnit Testing Spring Service and DAO (with In-Memory Database). It is available from Gihut in the Spring-MVC-JUnit-Testing directory.

Test Configuration Classes

These are identical to those required for Service and DAO testing.

Controller

Our controller:
@Controller
public class MyController {

    @Autowired
    private MyService myService;

    @RequestMapping(value = "/")
    public String home(Model model) {

        return "index";

    }

    @RequestMapping(value = "/roundtrip")
    public String persistenceStatus(Model model) {

        MilliTimeItem retr = myService.createAndRetrieve();
        model.addAttribute("RoundTrip", retr);

        return "roundtrip";

    }

}

Controller Testing

The following creates an instance of MockMvc to test simulated user requests:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ JpaTestConfig.class, TestConfig.class })
public class MyControllerTest {

    private MockMvc mockMvc;

    @Before
    public void setup() {

        mockMvc = MockMvcBuilders
            .annotationConfigSetup(JpaTestConfig.class, TestConfig.class)
            .build();

    }

    @Test
    public void testHome() throws Exception {

        mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(forwardedUrl("WEB-INF/pages/index.jsp"));

    }

    @Test
    public void testPersistenceStatus() throws Exception {

        mockMvc.perform(get("/roundtrip"))
            .andExpect(status().isOk())
            .andExpect(forwardedUrl("WEB-INF/pages/roundtrip.jsp"))
            .andExpect(model().attributeExists("RoundTrip"));

    }

}
The / request verifies the returned status and the URL mapping to the JSP page. The /roundtrip request makes sure the returned model does contain the Roundtrip attribute.

Dependencies

The Spring MVC test artifact is not yet available from maven's central repository. It should be obtained from another repository:
<repositories>
    <repository>
        <id>spring.test-mvc</id>
        <url>http://repo.springsource.org/libs-milestone</url>
    </repository>
</repositories>
The required dependency are:
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test-mvc</artifactId>
    <version>1.0.0.M1</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.hamcrest</groupId>
    <artifactId>hamcrest-library</artifactId>
    <version>1.3</version>
    <scope>test</scope>
</dependency>

More Spring related posts here.

Tuesday, 4 September 2012

JUnit Testing Spring Service and DAO (with In-Memory Database)

This post describes how to implement JUnit tests for a Spring Web Application's Services and DAO. It is built on top of the Spring MVC-Service-DAO-Persistence Architecture Example. This example is available from Github in the Spring-Web-JPA-Testing directory.

Reminder

  • Test Fixture - The fixed state used as a baseline for running tests.
  • Unit test - These tests verify that pieces of code (components) perform some functionalities as expected. In a Java environment, these are typically implemented at the class level.
  • Integration test - Integration testing is any type of test checking that a set of interacting components perform expected functionalities together correctly.

Configuration

We need a JPA Hibernate configuration for in-memory testing:
@Configuration
@EnableTransactionManagement
public class JpaTestConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactoryBean(){

        LocalContainerEntityManagerFactoryBean lcemfb
            = new LocalContainerEntityManagerFactoryBean();

        lcemfb.setDataSource(this.dataSource());
        lcemfb.setPackagesToScan(new String[] {"com.jverstry"});
        lcemfb.setPersistenceUnitName("MyTestPU");

        HibernateJpaVendorAdapter va = new HibernateJpaVendorAdapter();
        lcemfb.setJpaVendorAdapter(va);

        Properties ps = new Properties();
        ps.put("hibernate.dialect", "org.hibernate.dialect.HSQLDialect");
        ps.put("hibernate.hbm2ddl.auto", "create");
        lcemfb.setJpaProperties(ps);

        lcemfb.afterPropertiesSet();

        return lcemfb;

    }

    @Bean
    public DataSource dataSource(){

        DriverManagerDataSource ds = new DriverManagerDataSource();

        ds.setDriverClassName("org.hsqldb.jdbcDriver");
        ds.setUrl("jdbc:hsqldb:mem:testdb");
        ds.setUsername("sa");
        ds.setPassword("");

        return ds;

    }

    @Bean
    public PlatformTransactionManager transactionManager(){

        JpaTransactionManager tm = new JpaTransactionManager();

        tm.setEntityManagerFactory(
            this.entityManagerFactoryBean().getObject() );

        return tm;

    }

    @Bean
    public PersistenceExceptionTranslationPostProcessor exceptionTranslation(){
        return new PersistenceExceptionTranslationPostProcessor();
    }

}
We need to exclude the production configuration from package scanning (no "com.jverstry" scanning):
@Configuration
@ComponentScan(basePackages = {
    "com.jverstry.Controller",
    "com.jverstry.DAO",
    "com.jverstry.Item",
    "com.jverstry.Service"
})

public class TestConfig {

    @Bean
    public MyService getMyService() {
        return new MyServiceImpl();
    }

}

Spring Testing Tools

  • @RunWith - This is a JUnit annotation allowing one to run a test with a different runner than the one provided by JUnit.
  • SpringJUnit4ClassRunner - This is a JUnit test runner for Spring applications. Typically, test classes are annoted with @RunWith(SpringJUnit4ClassRunner.class)
  • @ContextConfiguration - This annotation can be used to specify how to load an applicationContext in Spring test class. This can be configured via XML files or Java configuration objects.

Service Testing

The following class tests the createAndRetrieve() method of our injected MyService implementation:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ JpaTestConfig.class, TestConfig.class })
public class MyServiceImplTest {

    @Autowired
    private MyService myService;

    @Test
    public void testCreateAndRetrieve() {

        MilliTimeItem retr = myService.createAndRetrieve();

        assertNotNull(retr);

    }

}

DAO Testing

The following class tests our DAO implementation. Our implementation is injected with an EntityManager created from our test configuration class defined above.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes={ JpaTestConfig.class, TestConfig.class })
public class MyPersistenceDAOTest {

    @Autowired
    private MyPersistenceDAO myDAO;

    @Test
    public void testCreateMilliTimeItem() {

        // This operation should not throw an Exception
        long id = myDAO.createMilliTimeItem();

    }

    @Test
    public void testGetMilliTimeItem() {

        long id = myDAO.createMilliTimeItem();
        MilliTimeItem retr = myDAO.getMilliTimeItem(id);

        assertNotNull(retr);
        assertEquals(id,retr.getID());

    }

}

Caveat

When starting to write JUnit tests for Spring, one can come across the following error messages:
Java.lang.ClassFormatError:
Absent Code attribute in method that is not native or abstract in class file javax/validation/Validation
The above is often caused by the following maven dependency:
         <dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>6.0</version>
            <type>jar</type>
         </dependency>
It should be replaced with:
           <dependency>
               <groupId>org.apache.geronimo.specs</groupId>
               <artifactId>geronimo-jpa_2.0_spec</artifactId>
               <version>1.1</version>
               <scope>provided</scope>
           </dependency>
Another error message is:
javax.validation.ValidationException: Unable to find a default provider
This is solved by adding the following maven dependency:
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.3.0.Final</version>
        </dependency>

For Spring MVC Controller JUnit testing, see here • More Spring related posts here.