views:

70

answers:

2

Hi there,

I'm trying to write some unit tests for my controllers in a Spring MVC web app. I have already got a fairly comprehensive set of unit tests for the domain model, but for completeness I want to test the controllers too.

The issue I'm facing is trying to test them without loading a Spring context. I thought I could get around this with mocking, but the method in the controller has a @Transactional annotation which attempts to open a transaction (and fails with a NullPointerException because no Spring context is loaded).

Code example:

public class UsersController {

  @Autowired private UserManager userManager;

  @Transactional
  @RequestMapping(method = RequestMethod.POST)
  public ModelAndView create(User user) {

    userManager.save(user);

    ModalAndView mav = new ModelAndView();    
    mav.addObject("user", user);
    mav.setViewName("users/view");
    return mav;
  }

}

So essentially I want to test the behaviour without loading a context and actually persisting the user.

Does anyone have any ideas on how I can achieve this?

Cheers,

Caps

+3  A: 

I'd say mocking is the way to go here. The @Transactional annotation will have no effect unless there is a Spring context loaded and instructed to configure annotation-based transactions.

Make sure that you aren't instructing JUnit to run your test within a spring context by specifying something like:

@ContextConfiguration(locations = "classpath:spring/ITestAssembly.xml")
@RunWith(SpringJUnit4ClassRunner.class)

To prevent confusion, I keep my unit tests (not running in a spring context) in separate files than my integration tests. Typically all mocking occurs in the unit tests and not in integration tests.

oksayt
Yep I've pulled out the spring context and mocked the UserManager and all is good.
Caps
+1  A: 

The NullPointerException occurs not because of the Transactional, but because nothing gets injectedas UserManager. You have two options:

  • run with the spring test runner
  • mock the userManager and set it.
Bozho
Thanks for your help, I've gone with the second option.
Caps