What is the best way to test controllers and services using JUnit?

I have this Spring MVC controller:

@Controller @RequestMapping(value = "/foo") public class FooController { @Inject private FooService fooService; @RequestMapping(value = "foo/new") public final String add(final ModelMap model) { model.addAttribute(fooService.createFoo()); return "foo/detail"; } @RequestMapping(value = "foo/{id}") public final String detail(final ModelMap model, @PathVariable long id) { model.addAttribute(fooService.findById(id)); return "foo/detail"; } @RequestMapping(value="foo/update", method=RequestMethod.POST) public final String save(@Valid @ModelAttribute final Foo foo, final BindingResult result, final SessionStatus status, final RedirectAttributes ra, final HttpServletRequest request) { if (result.hasErrors()) { return "foo/detail"; } fooService.save(foo); status.setComplete(); Message.success(ra, "message.ok"); return "redirect:foo/list"; } @RequestMapping( value= "/foo/delete/{id}", method=RequestMethod.POST) public String delete(@PathVariable final Long id, final SessionStatus status, final RedirectAttributes ra, final HttpServletRequest request){ if (fooService.findByIdWithOtherFoos(id).getOtherFoos().isEmpty()) { fooService.delete(id); status.setComplete(); MessageHelper.success(ra, "message.sucess"); } else { Message.error(ra, "message.error"); } return "redirect:foo/list"; } } 

And this service:

 @Service @Transactional(readOnly = true) public class FooServiceImpl implements FooService { @Inject private fooRepository fooRepo; @Override public final Foo createFoo() { return new Foo(); } @Override @Transactional(readOnly = false) public final void save(final Foo foo) { if (foo.getId() == null) { foo.setDate(new Date()); } fooRepo.save(foo); } @Override @Transactional(readOnly = false) public final void delete(final Long id) { fooRepo.delete(id); } @Override public final Foo findById(final Long id) { return fooRepo.findOne(id); } @Override public Foo findByIdWithOtherFoos(Long id) { Foo foo = fooRepo.findOne(id); Hibernate.initialize(foo.getOtherFoos()); return foo; } @Override public final Page<Foo> findAll(final Pageable pageable) { return fooRepo.findAll(pageable); } @Override public final Page<Foo> find(final String filter, final Pageable pageable) { // TODO Auto-generated method stub return null; } @Override public final List<Foo> findAll(final Sort sort) { return fooRepo.findAll(sort); } } 

What is the best way to test JUnit drivers and services to cover all logical conditions? I always end up with a bunch of test lines to cover all the logical conditions.

We recommend using MockitoJUnitRunner? Or create classes that create beans configuration. And charge them with ContextConfiguration 'ContextConfiguration (FooServiceImplTestConfiguration.class classes = {})'

How to implement a Given-When-Then template?

+8
java spring junit
source share
7 answers

Finally, I use this solution.

For my domain model, I use this link http://www.javacodegeeks.com/2014/09/tips-for-unit-testing-javabeans.html

 /** * @param <T> */ public abstract class AbstractJavaBeanTest<T> { protected String[] propertiesToBeIgnored; protected abstract T getBeanInstance(); @Test public void beanIsSerializable() throws Exception { final T myBean = getBeanInstance(); final byte[] serializedMyBean = SerializationUtils.serialize((Serializable) myBean); @SuppressWarnings("unchecked") final T deserializedMyBean = (T) SerializationUtils.deserialize(serializedMyBean); assertEquals(myBean, deserializedMyBean); } @Test public void equalsAndHashCodeContract() { EqualsVerifier.forClass(getBeanInstance().getClass()).suppress(Warning.STRICT_INHERITANCE, Warning.NONFINAL_FIELDS).verify(); } @Test public void getterAndSetterCorrectness() throws Exception { final BeanTester beanTester = new BeanTester(); beanTester.getFactoryCollection().addFactory(LocalDateTime.class, new LocalDateTimeFactory()); beanTester.testBean(getBeanInstance().getClass()); } class LocalDateTimeFactory implements Factory { @Override public LocalDateTime create() { return LocalDateTime.now(); } } } /** * Test Foo */ public class FooTest extends AbstractJavaBeanTest<Foo> { @Override protected Foo getBeanInstance() { return new Foo(); } } 

I add these dependencies to pom.xml:

 <dependency> <groupId>nl.jqno.equalsverifier</groupId> <artifactId>equalsverifier</artifactId> <version>1.7.6</version> <scope>test</scope> </dependency> <dependency> <groupId>org.meanbean</groupId> <artifactId>meanbean</artifactId> <version>2.0.3</version> </dependency> 

For my MVC controllers, I use this link http://www.luckyryan.com/2013/08/24/unit-test-controllers-spring-mvc-test/

 /** * Test FooController */ public class FooControllerTest { @Mock private FooService fooService; @InjectMocks private FooController fooController; private MockMvc mockMvc; @Before public void setup() { // Process mock annotations MockitoAnnotations.initMocks(this); // Setup Spring test in standalone mode this.mockMvc = MockMvcBuilders.standaloneSetup(fooController).build(); } @Test public void testAdd() throws Exception { Foo foo = new Foo(); // given given(FooService.createFoo()).willReturn(foo); // when // then this.mockMvc.perform(get("/foo/new")) .andExpect(forwardedUrl("foo/detail")) .andExpect(model().attributeExists("foo")) .andExpect(model().attribute("foo", is(foo))); } @Test public void testDetail() throws Exception { Foo foo = new Foo(); Long fooId = 1L; // given given(fooService.findById(fooId)).willReturn(foo); // when // then this.mockMvc.perform(get("/foo/" + fooId)) .andExpect(forwardedUrl("foo/detail")) .andExpect(view().name("foo/detail")) .andExpect(model().attributeExists("foo")) .andExpect(model().attribute("foo", is(foo))); } @Test public void testSave() throws Exception { Foo foo = new Foo(); // given // when // then //With form errors this.mockMvc.perform(post("/foo/update") .param("name", "") .sessionAttr("foo", foo)) .andExpect(forwardedUrl("foo/detail")) .andExpect(model().hasErrors()) .andExpect(model().attributeHasFieldErrors("foo", "name")); //Without form errores this.mockMvc.perform(post("/foo/update") .param("name", "nameValue") .param("code", "codeValue") .param("date", "20/10/2015") .requestAttr("referer", "/foo/list") .sessionAttr("foo", foo)) .andExpect(view().name("redirect:" + "/foo/list")) .andExpect(model().hasNoErrors()) .andExpect(flash().attributeExists("message")) .andExpect(flash().attribute("message", hasProperty("message", is("message.ok")))) .andExpect(flash().attribute("message", hasProperty("type", is(Message.Type.SUCCESS)))) .andExpect(status().isFound()); } @Test public void testDelete() throws Exception { Foo foo = new Foo(); foo.setOtherFoos(new ArrayList<OtherFoo>()); Long fooId = 1L; // given given(fooService.findByIdWithOtherFoos(fooId)).willReturn(foo); // when // then //Without errors: without other foos this.mockMvc.perform(post("/foo/delete/" + fooId) .sessionAttr("foo", foo) .requestAttr("referer", "/foo/list")) .andExpect(view().name("redirect:" + "/foo/list")) .andExpect(flash().attributeExists("message")) .andExpect(flash().attribute("message", hasProperty("message", is("message.ok")))) .andExpect(flash().attribute("message", hasProperty("type", is(Message.Type.SUCCESS)))); // given foo.getOtherFoos().add(new OtherFoo()); given(fooService.findByIdWithOtherFoos(fooId)).willReturn(foo); // when // then //With errors: with other foos this.mockMvc.perform(post("/foo/delete/" + fooId) .sessionAttr("foo", foo) .requestAttr("referer", "/foo/list")) .andExpect(view().name("redirect:" + "/foo/list")) .andExpect(flash().attributeExists("message")) .andExpect(flash().attribute("message", hasProperty("message", is("message.error")))) .andExpect(flash().attribute("message", hasProperty("type", is(Message.Type.DANGER)))); } } 

For my JUnit service test, I implemented a class for configuration and loaded it in the service test

 @Configuration public class FooServiceImplTestConfiguration { @Bean public FooService fooService() { return new FooServiceImpl(); } @Bean public FooRepository fooRepository() { return Mockito.mock(FooRepository.class); } } @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = {FooServiceImplTestConfiguration.class}) public class FooServiceImplTest { @Inject private FooRepository fooRepository;; @Inject private FooService fooService; @BeforeClass public static void oneTimeSetUp() { // one-time initialization code System.out.println("@BeforeClass - oneTimeSetUp"); } @AfterClass public static void oneTimeTearDown() { // one-time cleanup code System.out.println("@AfterClass - oneTimeTearDown"); } @Before public void setUp() { } @After public void tearDown() { } @Test public void createFoo() { assertNotNull(fooService.createFoo()); } @Test public void save() { //New foo Foo saveFoo = new Foo(); // given // when fooService.save(saveFoo); // then assertNotNull(saveFoo.getDate()); saveFoo.setId(1L); Date date = new Date(); saveFoo.setDate(date); // given //when fooService.save(saveFoo); //then assertThat(date, is(saveFoo.getDate())); } @Test public void delete() { //given //when fooService.deleteFoo(Matchers.anyLong()); //then } @Test public void findById() { Long id = 1L; Foo fooResult = new Foo(); //given given(fooRepository.findOne(id)).willReturn(fooResult); //when Foo foo = fooService.findById(id); //then assertThat(foo, is(fooResult)); } @Test public void findByIdWithOtherFoos() { Long id = 1L; Foo fooResult = new Foo(); //given given(fooRepository.findOne(id)).willReturn(fooResult); //when Foo foo = fooService.findByIdWithOtherFoos(id); //then assertThat(foo, is(fooResult)); } @Test public void findAll() { Page<Foo> fooResult = new PageImpl<>(new ArrayList<Foo>()); given(fooRepository.findAll(Matchers.<Pageable>anyObject())).willReturn(fooResult); //when Page<Foo> foos = fooService.findAll(Matchers.<Pageable>anyObject()); //then assertThat(foos, is(fooResult)); } @Test public void findAllList() { List<Foo> fooResult = new ArrayList<Foo>(); given(fooRepository.findAll(Matchers.<Sort>anyObject())).willReturn(fooResult); //when List<Foo> foos = fooService.findAll(Matchers.<Sort>anyObject()); //then assertThat(foos, is(fooResult)); } } 

In my pom, I need to add these dependencies:

 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.2.3.RELEASE</version> </dependency> <!-- This is for mocking the service --> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.5</version> <scope>test</scope> </dependency> <!-- Optional --> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-core</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-library</artifactId> <version>1.3</version> <scope>test</scope> </dependency> 

I need to change the check version for sleep mode for this:

 <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>5.1.3.Final</version> </dependency> 

I also need to add these dependencies because I got this exception:

Reason: java.lang.AbstractMethodError: org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultParameterNameProvider () Ljavax / validation / ParameterNameProvider;

Detailed message: org.hibernate.validator.internal.engine.ConfigurationImpl.getDefaultParameterNameProvider () Ljavax / validation / ParameterNameProvider;

 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>3.1.0</version> </dependency> <dependency> <groupId>org.glassfish.web</groupId> <artifactId>el-impl</artifactId> <version>2.2</version> </dependency> 

I use spring data, I also need to run a test for my own CrudRepositories.

0
source share

When it comes to testing controllers (especially for integration testing), I suggest using Spring MockMVC or Rest-Assured . And an example of using Rest-Assured in action can be seen below:

 @RunWith(SpringJUnit4ClassRunner.class) @SpringApplicationConfiguration(classes = SomeApplication.class) @WebIntegrationTest(randomPort = true) @ActiveProfiles(profiles = "test") @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_CLASS) public class SomeControllerTest { @Test public void getAllSomeObjects() { expect().statusCode(HttpStatus.SC_OK) .body("", hasSize(2)) .body("[0]", notNullValue()) .body("[1]", notNullValue()) .body("findAll { it.name.equals('TEST1') }", hasSize(1)) .body("findAll { it.name.equals('TEST2') }", hasSize(1)) .when() .get("/someAddress"); } } 

For testing services, I suggest using Mockito . Additionally, Hamcrest Matchers is a useful library for test claims. An example of using both below:

 public class SomeServiceTest { @InjectMocks private SomeService someService; @Mock private SomeInnerService someInnerService; @Before public void setUp() { initMocks(this); Mockito.when(someInnerService.useMethod("argument")).thenReturn(new SomeObject()); } @Test public void testSomeMethod() { Set<SomeObject> someObjects= someService.someMethod(); assertThat(someObjects, is(notNullValue())); assertThat(someObjects, is(hasSize(4))); } } 
+3
source share

You should check both options yourself.

First create a unit test for your service. You can use Mockito to make fun of your service dependency as fooRepository.

 @Test public void testFindById() { when(fooServices.findById(123)).thenReturn(fooSample); assertThat(what you want); } 

Then you must create another unit test for your controller. The easiest way to do this is to use the MockMvc specified in spring -test. And in this case, you can use Mockito to fake fooService.

+2
source share

The best part. Use the spring MVC test layer. Because they provide their own API, which helps you mock controllers and provide you with session objects that you can fill with the required state. You can find many examples on the Internet. http://www.petrikainulainen.net/spring-mvc-test-tutorial/ You can test all your layers separately. All the best!

+2
source share

Check out Spring-Test-MVC . This is the basis for this purpose and comes with many easy-to-understand and reassembled examples.

Personally, I add Mockito / PowerMock to the mix for mocking internal dependencies.

Good luck.

+1
source share

It depends on which test you want to implement.

Of course Spring Test helps with this. This module supports unit testing and integration. Please note that unit tests are not really true unit tests, because when using the Spring test, context loading is the minimum value.

Check out the MockMvc class that you can use to query controllers.

+1
source share

I think the best way is to use ContextConfiguration in combination with DirtiesContext , MockMvcBuilders and Mockito. This gives you the advantage of creating a Spring controller through the application and beans input context, whose behavior is defined through Mockito. In this case, you can achieve a high level and coverage of conditions. Here is an example of your code:

 @ContextConfiguration @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @RunWith(SpringJUnit4ClassRunner.class) public class FooControllerTest { private MockMvc mockMvc; @Autowired private FooService service; @Autowired private FooController controller; @Before public void initController() { mockMvc = MockMvcBuilders.standaloneSetup(frontEndController).build(); } @Test public void shouldDoSomeThing_CornerCase() { // Given: // define the behaviour of service with when(service...) // Then: // perform a request on contoller mockMvc.perform(get("/foo/delete/{id}")) // When: // user Mockito verify // or // MockMvcRequestBuilders } @Configuration public static class FooConfiguration { @Bean public FooController controller() { return new FooController(); } @Bean public FooService service() { return mock(FooService.class); } } } 

DirtiesContext it is important that you get pure mockery of each test.

+1
source share

All Articles