009 spring mvc controller unit test

009 spring mvc controller unit test

视频发布在youtube上面了
https://youtu.be/d-u95Q5JJjs
优酷上面的链接
http://v.youku.com/v_show/id_XMjgxNDY1Nzc4MA==.html?f=49760672

接着008的项目操作。

首先处理一下008中分页显示的时候,500000条记录,页号显示不全的问题。
我这里使用的是themes-default风格。在这里找到easyui.css,里面找到
pagination-num,修改width属性即可。原来是2,我改成了10,顺便了解了一下CSS Units。

em  Relative to the font-size of the element (2em means 2 times the size of the current font)

这里有详细介绍
https://www.w3schools.com/cssref/css_units.asp

.pagination .pagination-num {
  border-width: 1px;
  border-style: solid;
  margin: 0 2px;
  padding: 2px;
  width: 10em;
  height: auto;
}

刷新一下就可以看到变化了。注意如果没有变化清空一下浏览器缓存,在浏览器端检查一下,easyui.css源码是否是修改过后的。

自定义PageList数,非常的方便,设置对应的属性就可以了。
pageSize:12,pageList:[12,100,200,300]

<table id="dg" class="easyui-datagrid" title="用户列表"
    style="width: 100%; height: 400px;pagination-num{width:200px}"
    data-options="rownumbers:true,striped:true,fitColumns:true,singleSelect:true,autoRowHeight:true,pagination:true,
      pageSize:12,pageList:[12,100,200,300],url:'${pageContext.request.contextPath}/getUsers',method:'get',toolbar:'#toolbar'">

TestGetUser增加一个断言判断user是否为空

...
assertTrue(user != null);
assertTrue(user.getName().equals("user1"));

增加测试依赖包

<!-- controller test -->
<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path-assert</artifactId>
    <version>2.2.0</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-all</artifactId>
    <version>1.10.19</version>
    <scope>test</scope>
</dependency>

JsonPath 用来写JSON数据的断言判断的。下面是网址
https://github.com/json-path/JsonPath

新建测试类TestUserController,这里使用实际的service来操作数据库获取数据。
这个用来控制测试函数的执行顺序,添加,更新,删除,执行完毕后,对数据没有影响。
@FixMethodOrder(MethodSorters.NAME_ASCENDING)

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:springmvc.xml")
@WebAppConfiguration
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestUserController
{
    public static final MediaType APPLICATION_JSON_UTF8 = new MediaType(MediaType.APPLICATION_JSON.getType(),
            MediaType.APPLICATION_JSON.getSubtype(), Charset.forName("utf8"));

    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    private static String lastNewId;

    @Before
    public void init()
    {
        mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
    }

    @Test
    public void testReturnPage() throws Exception
    {
        mockMvc.perform(get("/users")).andExpect(status().isOk()).andExpect(view().name("users")).andDo(print());
    }

    @Test
    public void testRealApiGetUsers() throws Exception
    {
        // .accept方法是设置客户端可识别的内容类型
        // .contentType,设置请求头中的Content-Type字段,表示请求体的内容类型
        mockMvc.perform(get("/getUsers").accept(MediaType.APPLICATION_JSON_UTF8)
                .contentType(MediaType.APPLICATION_JSON_UTF8).param("page", "1").param("rows", "10")).andDo(print())
                .andExpect(status().isOk()).andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$.total").exists()).andExpect(jsonPath("$.rows").isArray())
                .andExpect(jsonPath("$.rows", hasSize(10)));
    }

    @Test
    public void test001RealApiAddUser() throws Exception
    {
        MvcResult ret = mockMvc
                .perform(post("/users").accept(MediaType.APPLICATION_JSON_UTF8)
                        .contentType(MediaType.APPLICATION_JSON_UTF8).param("name", "user1").param("age", "23")
                        .param("gender", "女").param("email", "user1@126.com").param("teacherId", "1")
                        .param("createTime", "2017-06-08 13:59:12").param("loginTime", "2017-06-08 13:59:12"))
                .andDo(print()).andExpect(status().isOk())
                .andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$.retCode").value(0)).andExpect(jsonPath("$.newId").exists()).andReturn();
        MockHttpServletResponse resp = ret.getResponse();
        String strContent = resp.getContentAsString();
        JSONObject jsonObject = JSONObject.parseObject(strContent);
        lastNewId = jsonObject.get("newId").toString();
    }

    @Test
    public void test002RealApiUpdateUser() throws Exception
    {
        mockMvc.perform(put("/users/" + lastNewId).accept(MediaType.APPLICATION_JSON_UTF8)
                        .contentType(MediaType.APPLICATION_JSON_UTF8).param("name", "user1").param("age", "33")
                        .param("gender", "男").param("email", "user1@126.com").param("teacherId", "2")
                        .param("createTime", "2017-06-08 13:59:12").param("loginTime", "2017-06-08 13:59:12"))
                .andDo(print()).andExpect(status().isOk())
                .andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$.retCode").value(0)).andExpect(jsonPath("$.status").value("更新成功"));

    }

    @Test
    public void test003RealApiDeleteUser() throws Exception
    {
        mockMvc.perform(delete("/users/" + lastNewId).accept(MediaType.APPLICATION_JSON_UTF8)
                .contentType(MediaType.APPLICATION_JSON_UTF8)).andDo(print()).andExpect(status().isOk())
                .andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$.retCode").value(0)).andExpect(jsonPath("$.status").value("删除成功"));
    }
}

在UserController里面做了点修改,添加用户的时候返回了该条记录的主键。顺便把返回类型改成了JSONObject

@RequestMapping(value = "/users", method = RequestMethod.POST)
@ResponseBody
public JSONObject addUserProc(User user)
{
    // 处理新id生成
    // 处理teacher类对象
    user.setTeacher(teacherService.getTeacherById(user.getTeacherId()));
    int iRet = userService.insertUser(user);
    long newId = user.getId();
    JSONObject jsonObject = new JSONObject();
    if (iRet == 0)
    {
        logger.info("addUsersProc: " + JSON.toJSON("新建失败:" + JSON.toJSONStringWithDateFormat(user, "yyyy-MM-dd HH:mm:ss")));
        jsonObject.put("status", "新建失败");
        jsonObject.put("retCode", -1);
    } else
    {
        logger.info("addUsersProc: " + JSON.toJSON("新建用户:" + JSON.toJSONStringWithDateFormat(user, "yyyy-MM-dd HH:mm:ss")));
        jsonObject.put("status", "新建成功");
        jsonObject.put("retCode", 0);
        jsonObject.put("newId", newId);
    }
    return jsonObject;
}

需要手动引入两个包,不知道为什么不能自动引入。
MethodSorters的作用,这里需求是希望测试函数按照顺序执行,先添加一条记录,获取ID,然后再使用ID删除刚刚添加的记录。

import static org.hamcrest.Matchers.hasSize;
import org.junit.runners.MethodSorters;

现在可以右键-Run As选择JUnit Test

Mock Service测试

新建一个TestUserControllerMockService测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:springmvc.xml")
@WebAppConfiguration
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class TestUserControllerMockService
{
    @Autowired
    private WebApplicationContext wac;

    private MockMvc mockMvc;

    @InjectMocks
    private UserController userController;

    @Mock
    private IUserService userService;

    @Before
    public void init()
    {
        //support @Mock annotation
        MockitoAnnotations.initMocks(this);

        //解决Controller返回字符串和Mapping字符串相同时提示错误的问题
        InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
        viewResolver.setPrefix("/WEB-INF/views/");
        viewResolver.setSuffix(".jsp");

        FastJsonHttpMessageConverter fastjsonMsgConv = this.wac.getBean(com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter.class);
        StringHttpMessageConverter stringMsgConv = this.wac.getBean(StringHttpMessageConverter.class);
        mockMvc = MockMvcBuilders.standaloneSetup(userController)
                .setViewResolvers(viewResolver)
                .setMessageConverters(fastjsonMsgConv,stringMsgConv)
                .build();
    }

    @Test
    public void testApiGetUsers() throws Exception
    {
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = null;
        try
        {
            date = df.parse("2017-06-08 13:59:12");
        } catch (ParseException e)
        {
            e.printStackTrace();
        }
        List<User> users = new ArrayList<User>();

        for (int i = 0; i < 3; ++i)
        {
            User user = new User();
            user.setId(1L + i);
            user.setName("user" + Integer.toString(i + 1));
            user.setAge(23 + i);
            user.setGender("女");
            user.setEmail("user1@126.com");
            user.setTeacherId(1L);
            user.setCreateTime(date);
            user.setLoginTime(date);

            users.add(user);
        }

        when(userService.getCount()).thenReturn(3L);
        when(userService.getUsersPagenition(1, 3)).thenReturn(users);

        mockMvc.perform(get("/getUsers").accept(MediaType.APPLICATION_JSON_UTF8)
                .contentType(MediaType.APPLICATION_JSON_UTF8).param("page", "1").param("rows", "3")).andDo(print())
                .andExpect(status().isOk()).andExpect(content().contentType("application/json;charset=UTF-8"))
                .andExpect(jsonPath("$.total").exists()).andExpect(jsonPath("$.rows").isArray())
                .andExpect(jsonPath("$.rows", hasSize(3)))
                .andExpect(jsonPath("$.rows[0].name").value("user1"))
                .andExpect(jsonPath("$.rows[0].gender").value("女"))
                .andExpect(jsonPath("$.rows[0].age").value(23))
                .andExpect(jsonPath("$.rows[1].name").value("user2"))
                .andExpect(jsonPath("$.rows[1].age").value(24));       
        //verify Interactions with any mock
        verify(userService, times(1)).getCount();
        verify(userService, times(1)).getUsersPagenition(1, 3);
        verifyNoMoreInteractions(userService);

    }
}

@Mock: 需要被Mock的对象
@InjectMocks: 需要将Mock对象注入的对象, 此处就是Controller
下面这个是
MockitoAnnotations.initMocks(this);
@Before
初始化Mock对象, 通过MockMvcBuilders.standaloneSetup模拟一个Mvc测试环境,注入controller, 通过build得到一个MockMvc, 后面就用MockMvc的一些API做测试。
这里面因为使用了fastJson发现之前的springmvc配置需要修改一下,才能通过。暂时先保证学习进度,后面有机会再深入了解一下fastJson的相关配置。
相关错误提示

No qualifying bean of type 'com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter' available
<!-- 对于mvc没有映射过的请求,交给容器默认handler来处理,例如:js,css等静态资源 -->
<mvc:default-servlet-handler />
<!-- FastJson 转换注册 -->
<bean id="stringHttpMessageConverter"
    class="org.springframework.http.converter.StringHttpMessageConverter">
    <constructor-arg value="UTF-8" index="0"></constructor-arg>
    <property name="supportedMediaTypes">
        <list>
            <value>text/plain;charset=UTF-8</value>
        </list>
    </property>
</bean>
<bean id="fastJsonHttpMessageConverter"
    class="com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter">
    <property name="supportedMediaTypes">
        <list>
            <value>text/html;charset=UTF-8</value>
            <value>application/json;charset=UTF-8</value>
        </list>
    </property>
    <!--设置fastjson特性 -->
    <property name="features">
        <array>
            <!--设置null值也要输出,fastjson默认是关闭的 -->
            <value>WriteMapNullValue</value>
            <!--设置使用文本方式输出日期,fastjson默认是long -->
            <value>WriteDateUseDateFormat</value>
        </array>
    </property>
    <property name="fastJsonConfig">
        <bean class="com.alibaba.fastjson.support.config.FastJsonConfig">
            <property name="features">
                <list>
                    <value>AllowArbitraryCommas</value>
                    <value>AllowUnQuotedFieldNames</value>
                    <value>DisableCircularReferenceDetect</value>
                </list>
            </property>
            <property name="dateFormat" value="yyyy-MM-dd HH:mm:ss"></property>
        </bean>
    </property>
</bean>
<mvc:annotation-driven conversion-service="conversionService">
    <mvc:message-converters register-defaults="true">
        <ref bean="stringHttpMessageConverter" />
        <ref bean="fastJsonHttpMessageConverter" />
    </mvc:message-converters>
</mvc:annotation-driven>

现在应该可以直接run这个测试了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值