Unit Test (Java Spring)

Pre-Action

  • Install J Unit and Mockito dependencies

E.g: Maven

	<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>

		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-core</artifactId>
			<version>2.23.0</version>
			<scope>test</scope>
		</dependency>
		
		<dependency>
			<groupId>org.mockito</groupId>
			<artifactId>mockito-junit-jupiter</artifactId>
			<version>2.23.0</version>
			<scope>test</scope>
		</dependency>

Stub vs Mock vs Spy

Stub vs Mock

  • Stub: Initialize -> Exercise -> Verify

private class FooStub implements Foo
{
    public String bar()
    {
        return"baz";
    }
}
public class FooCollectionTest
{
    @Test
    public void test()
    {   
        //Initialize 
        FooStub newFooStub = new FooStub();
        FooCollection sut = newFooCollection();
        sut.add(newFooStub.bar());
        sut.add(newFooStub.bar());
        //Exercise and Verify
        assertEquals("bazbaz",sut.joined());
    }
}
  • Mock: Initialize -> Set up expectations -> Exercise -> Verify

public class FooCollectionTest
{    
    @Mock
    FooStub newFooStub;
    
    //Initialize
    @InjectMock
    FooCollection sut ;
    
    @Test    
    public void test()
    {   
       
        // Setup expectations
        Mockito.doReturn("baz").when(newFooStub).bar();
        
        sut.add(newFooStub.bar());
        sut.add(newFooStub.bar());
        //Exercise and Verify
        assertEquals("bazbaz",sut.joined());
    }
}

Mock vs Spy

  • Spy will actually call the real method of the class , while mock doesn't

  • Spy

@Test
public void whenCreateSpy_thenCreate() {
    List spyList = Mockito.spy(new ArrayList());
 
    spyList.add("one");
    Mockito.verify(spyList).add("one");
 
    assertEquals(1, spyList.size());
}
  • Mock

@Test
public void whenCreateMock_thenCreated() {
    List mockedList = Mockito.mock(ArrayList.class);
 
    mockedList.add("one");
    Mockito.verify(mockedList).add("one");
 
    assertEquals(0, mockedList.size());
}

Mockito Method

doAnswer (used to mock the void type function)

Mockito.doAnswer(invocation->{
    if(invocation != null && invocation.getArguments().length > 0){
        System.out.println("Test Void");
    }
    return null;
}).when(productService).test(Integer input);

doReturn (used to mock the return value of function)

 Mockito.doReturn(0).when(shopService).test(any(Integer.class));

Service Testing Example

TestServiceImpl

package com.example.demo.service.impl;

import com.example.demo.service.ShopService;
import com.example.demo.service.TestService;

public class TestServiceImpl implements TestService {
    Integer addNumber = 2;
    ShopService shopService;
    @Override
    public Integer gg(){
        return 3;
    }

    @Override
    public void testVoid(){

    }
    @Override
    public Integer test(){
        Integer num = gg();
        Integer num2 = shopService.test(10);
        return 1 + num + num2;
    }

}

ShopServiceImpl

package com.example.demo.service.impl;

import com.example.demo.service.ShopService;

public class ShopServiceImpl implements ShopService {
    @Override
    public Integer test(Integer input){
        return input;
    }
}

testServiceTest

package com.example.demo.service;

import com.example.demo.service.impl.TestServiceImpl;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.MockitoJUnitRunner;


import static org.mockito.ArgumentMatchers.any;

@RunWith(MockitoJUnitRunner.class)
public class testServiceTest {

    @Mock
    private ShopService shopService;

    @InjectMocks
    private TestService testService;

      private TestService testService1;

    //Constructor
    public testServiceTest() {
        testService = new TestServiceImpl();
    }
    @Before
    public void setUp() throws Exception{
        testService1 = Mockito.spy(testService);
    }

    @Test
    public void testTest() throws Exception{
        Mockito.when(testService1.gg()).thenReturn(1);
        Mockito.doReturn(0).when(shopService).test(any(Integer.class));
        Mockito.doAnswer(invocationOnMock -> {
            if(invocationOnMock != null && invocationOnMock.getArguments().length>0){
                System.out.println("testvoid");
            }
            return null;
        }).when(testService1).testVoid();
        Integer result = testService1.test();
        Assert.assertSame(2,result);
    }

}

Controller Unit Test

MockMvc

  • Create a new MockMvc Object as a entry point, so that we can use it to call the link of API

@RunWith(MockitoJUnitRunner.class)
public class schoolControllerTest
{
    private MockMvc mockMvc;
    
    private SchoolController schoolController;
    
    @Before
    public void setUp() throws NotFoundException{
        this.mockMvc = MockMvcBuilders.standaloneSetup(schoolController).build();
    } 
}
  • Method

@Test  
public void testView() throws Exception {  
 MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/user/1"))  
            .andExpect(MockMvcResultMatchers.view().name("user/view"))  
            .andExpect(MockMvcResultMatchers.model().attributeExists("user"))  
            .andDo(MockMvcResultHandlers.print())  
            .andReturn();  
}  
  • perform: make a request to api end point

  • andExpect: verify the result whether the actual is equal to actual or not

  • andDo: to make a handling after getting the result, such as print out the response

  • andReturn: return back to MvcResult

MockMvcRequestBuilders

  • Used to create a request

  • Methods

MockHttpServletRequestBuilder get(String urlTemplate, Object... urlVariables):根据uri模板和uri变量值得到一个GET请求方式的MockHttpServletRequestBuilder;如get(/user/{id}, 1L);

MockHttpServletRequestBuilder post(String urlTemplate, Object... urlVariables):同get类似,但是是POST方法;

MockHttpServletRequestBuilder put(String urlTemplate, Object... urlVariables):同get类似,但是是PUT方法;

MockHttpServletRequestBuilder delete(String urlTemplate, Object... urlVariables) :同get类似,但是是DELETE方法;

MockHttpServletRequestBuilder options(String urlTemplate, Object... urlVariables):同get类似,但是是OPTIONS方法;

MockHttpServletRequestBuilder request(HttpMethod httpMethod, String urlTemplate, Object... urlVariables): 提供自己的Http请求方法及uri模板和uri变量,如上API都是委托给这个API;

MockMultipartHttpServletRequestBuilder fileUpload(String urlTemplate, Object... urlVariables):提供文件上传方式的请求,得到MockMultipartHttpServletRequestBuilder;

RequestBuilder asyncDispatch(final MvcResult mvcResult):创建一个从启动异步处理的请求的MvcResult进行异步分派的RequestBuilder;

MockMvcResultMatchers

  • used to match the result of api end point , such as content-type, https status, return value

  • Methods

HandlerResultMatchers handler():请求的Handler验证器,比如验证处理器类型/方法名;此处的Handler其实就是处理请求的控制器;

RequestResultMatchers request():得到RequestResultMatchers验证器;

ModelResultMatchers model():得到模型验证器;

ViewResultMatchers view():得到视图验证器;

FlashAttributeResultMatchers flash():得到Flash属性验证;

StatusResultMatchers status():得到响应状态验证器;

HeaderResultMatchers header():得到响应Header验证器;

CookieResultMatchers cookie():得到响应Cookie验证器;

ContentResultMatchers content():得到响应内容验证器;

JsonPathResultMatchers jsonPath(String expression, Object ... args)/ResultMatcher jsonPath  (String expression, Matcher matcher):得到Json表达式验证器;

XpathResultMatchers xpath(String expression, Object... args)/XpathResultMatchers xpath(String expression, Map<string, string=""> namespaces, Object... args):得到Xpath表达式验证器;

ResultMatcher forwardedUrl(final String expectedUrl):验证处理完请求后转发的url(绝对匹配);

ResultMatcher forwardedUrlPattern(final String urlPattern):验证处理完请求后转发的url(Ant风格模式匹配,@since spring4);

ResultMatcher redirectedUrl(final String expectedUrl):验证处理完请求后重定向的url(绝对匹配);

ResultMatcher redirectedUrlPattern(final String expectedUrl):验证处理完请求后重定向的url(Ant风格模式匹配,@since spring4)

MockMvcResultHandlers

  • used to print the whole of the response of api end point

Example

@Test
public void getInventoryByProductCodeTest1() throws Exception
{
  mockMvc.perform(MockMvcRequestBuilders.get("/api/getSchool"))
  .andExpect(MockMvcResultMatchers.status().isOk()) // Check the http status
  .andExpect(MockMvcResultMatchers.content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) // check the content type
  .andExpect(MockMvcResultMatchers.jsonPath("studentName").value("Tom")); // check the result
}

Reference

https://www.jianshu.com/p/91045b0415f0

Last updated

Was this helpful?