0

I have the following:

Controller class:

@Controller
@RequestMapping("/")
public class MainController {

    @Inject
    @Named("dbDaoService")
    IDaoService dbDaoService;

    @RequestMapping(method = RequestMethod.GET)
    public String init(ModelMap model) {
        List<Tags> tags = dbDaoService.getAllTags();
        model.addAttribute("tags", tags);
        return "create";
    }
}

Service class:

@Service("dbDaoService")
public class DBDaoService implements IDaoService {

    @PersistenceContext(unitName = "MyEntityManager")
    private EntityManager entityManager;

    @Override
    @Transactional
    public List<Tags> getAllTags() {
         if(tags == null) {
            TypedQuery<Tags> query = entityManager.createNamedQuery("Tags.findAll", Tags.class);
            tags = query.getResultList();
        }

        return tags;
    }
}

Test class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebConfig.class})
@WebAppConfiguration
public class MainControllerTest  {

    private MockMvc mockMvc;

    @Autowired
    private WebApplicationContext context;

    @Before
    public void setUp() throws Exception {
        mockMvc = MockMvcBuilders
                .webAppContextSetup(context)
                .build();
    }

    @Test
    public void init() throws Exception {
        Tags tag1 = new Tags("first");
        Tags tag2 = new Tags("second");

        DBDaoService mock = org.mockito.Mockito.mock(DBDaoService.class);
        when(mock.getAllTags()).thenReturn(Arrays.asList(tag1, tag2));

        mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(view().name("create"))
            .andExpect(forwardedUrl("/WEB-INF/views/create.jsp"))
            .andExpect(model().attribute("tags", hasItem(
                    allOf(
                            hasProperty("name", is("first"))
                    )
            )))
            .andExpect(model().attribute("tags", hasItem(
                    allOf(
                            hasProperty("name", is("second"))
                    )
            )));
    }
}

When I run MainControllerTest, it fails, because it gets "Tag" entities from DBDaoService (it means, from database), but I expect it will use mock service.

What's wrong?

Maciej Kowalski
  • 21,760
  • 10
  • 42
  • 54
user2611714
  • 123
  • 2
  • 9
  • It seems your service class is missing some lines of code. You use Override and Transactional, but there is no method. – Uwe Allner Feb 08 '17 at 08:36
  • Sorry, it's a typo. The code is correct. – user2611714 Feb 08 '17 at 08:39
  • Possible duplicate of [unit testing for spring mvc controller with Integer value as @RequestParam](http://stackoverflow.com/questions/39267966/unit-testing-for-spring-mvc-controller-with-integer-value-as-requestparam) – Sergii Bishyr Feb 08 '17 at 14:25

1 Answers1

3

The current test setup loads the spring configuration and uses the WebApplicationContext to handle request due to MockMvcBuilders.webAppContextSetup(context).build();. Thus mocked beans are ignored since they are not instructed to participate.

To interweave them the configuration should be updated to MockMvcBuilders.standaloneSetup(controller).build() instead.

The sample test case should look like below (note the additional mock for MainController and configuration update to MockMvcBuilders.standaloneSetup along with instruction to use Mockito annotation via MockitoAnnotations.initMocks)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {WebConfig.class})
@WebAppConfiguration
public class MainControllerTest  {

    private MockMvc mockMvc;

    @InjectMocks
    private MainController controller;

    @Mock
    private DBDaoService daoService;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);

        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/view/");
        viewResolver.setSuffix(".jsp");

        mockMvc = MockMvcBuilders.standaloneSetup(controller)
                             .setViewResolvers(viewResolver)
                             .build();

        Tags tag1 = new Tags("first");
        Tags tag2 = new Tags("second");

        when(daoService.getAllTags()).thenReturn(Arrays.asList(tag1, tag2));
    }

    @Test
    public void init() throws Exception {

        mockMvc.perform(get("/"))
            .andExpect(status().isOk())
            .andExpect(view().name("create"))
            .andExpect(forwardedUrl("/WEB-INF/views/create.jsp"))
            .andExpect(model().attribute("tags", hasItem(
                allOf(
                        hasProperty("name", is("first"))
                )
            )))
            .andExpect(model().attribute("tags", hasItem(
                allOf(
                        hasProperty("name", is("second"))
                )
            )));
    }
}
Bond - Java Bond
  • 3,662
  • 6
  • 34
  • 56
  • Ok, that's great! But I still have two problems.First: **andExpect(forwardedUrl("/WEB-INF/views/create.jsp"))** causes the error: **java.lang.AssertionError: Forwarded URL Expected :/WEB-INF/views/create.jsp Actual :create** – user2611714 Feb 08 '17 at 09:39
  • Second problem: **andExpect(model().attribute("tags", hasItem(allOf( hasProperty("name", is("first"))))))** works well, but the second **andExpect(model().attribute("tags", hasItem(allOf(hasProperty("name", is("second"))))))** throws the error **NoSuchMethodError: org.hamcrest.Matcher.describeMismatch(Ljava/lang/Object;Lorg/hamcrest/Description;)V** – user2611714 Feb 08 '17 at 09:42
  • Regarding first problem - see update. Explicit view resolver is required in case of standalone configuration – Bond - Java Bond Feb 08 '17 at 10:05
  • Regarding second problem (*unsure why one statement works and second fails*) - Could you try the steps described [here](http://stackoverflow.com/questions/7869711/getting-nosuchmethoderror-org-hamcrest-matcher-describemismatch-when-running) and [here](https://tedvinke.wordpress.com/2013/12/17/mixing-junit-hamcrest-and-mockito-explaining-nosuchmethoderror/) – Bond - Java Bond Feb 08 '17 at 10:36