How to use @ContextConfiguration to test Web Spring app locally and in memory?

Let's imagine a Spring 3.1 web mvc application using MySql via Hibernate JPA via DAO's.

One has to write tests for the controllers without deploying the application and using an in-memory database (like hsqldb:mem for example). In other words, one should be able to run tests on a local PC.

How can this be achieved? Can someone provide a detailed example of how to write tests for such a controller? How should @ContextConfiguration be configured? How to retrieve a WebApplicationContext for testing purposes locally? Should one maintain a hibernate-test.cfg.xml?

Update

I am not talking only about unit testing, I am talking about integration testing.

Solution

To make this complete on top of Sean Patrick Floyd's answer, here is a solution inspired from here:

Example of service:

public interface MarkingService {
    public String markItem(String item);
}

Example of controller using service

@Controller  
public class TestableController {

    @Autowired
    private MarkingService markerService;

    @RequestMapping(value = "mark/{name}")  
    public String mark(Model ui, @PathVariable String name){  

        String value = this.markerService.markItem(name);
        ui.addAttribute("mark-value", value);

        return "mark-show";  

    }  

}

Mock of service to test controller:

public class MarkingServiceMock implements MarkingService {

    @Override
    public String markItem(String item) {
        return "mockValue";
    }

}

Config object for test configuration:

@Configuration
public class TestableControllerConfig {

    // We return a mock to test the controller layer
    @Bean
    public MarkingService markingService() {
        return new MarkingServiceMock();
    }

}

Controller test:

@RunWith(SpringJUnit4ClassRunner.class)  
@ContextConfiguration(classes={TestableControllerConfig.class})
public class TestableControllerTest {

    // Will be injected with TestableControllerConfig.markingService()
    @Autowired
    private MarkingService markerService;

    @Test
    public void testController() {

        // ...

    }

}

Assuming the service layer relies on DAO's, it is easy to inject implementations based on in-memory db too.

Upvotes: 1

Views: 1614

Answers (1)

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 298818

Usually, you wouldn't test the whole setup. Write tests for the web layer and mock the persistence layer in them. Write separate tests for the service and persistence layer.

If you are going to test web controllers, use ModelAndViewAssert or the Mock versions of HttpServletRequest etc.

If on the other hand you want to test the whole setup, run automated web tests using HtmlUnit, Selenium etc., but do it on your real deployed app (of course on a non-public installation).

But in my opinion, if you want to test the big picture, you need to test the real thing. Mocking on a large scale gets very messy.

Upvotes: 1

Related Questions