大家在估做功能测试的时候,不知有没有发现,如果统一用utf-8作为编码,POST测试请求中如果带有汉字就会乱码。
{"box":[{"entityId":7,"id":7,"idea":"?????","jPAContext":{"insideTransaction":true,"jPAConfig":{"configName":"play","enabled":true,"insideTransaction":true,"jPAContext":{"$ref":".."},"jpql":{}}},"persistent":false,"type":1},{"entityId":8,"id":8,"idea":"???","jPAContext":{"$ref":"$.box[0].jPAContext"},"persistent":false,"type":5},{"idea":"???","jPAContext":{"$ref":"$.box[0].jPAContext"},"persistent":false,"type":3}],"code":"jack","entityId":1003,"id":1003,"ip":"192.168.1.122","jPAContext":{"$ref":"$.box[0].jPAContext"},"nick":"??","passwd":"jack2","persistent":true,"qqmail":"[email protected]"}
这个是一个典型的编码问题,但是我找遍play也没有找到相关的设置,只好用调试看看。
1.我在从yml文件读取数据过程,我发现数据还不是乱码
2.在请求到达第七章提及的ActionInvoker中的时候,已经乱码。
所以我推测,应该是play框架对POST请求进行封装是出了问题在所有功能测试父类FunctionalTest中,重载了许多POST方法,其中根本是这个POST: play.test.FunctionalTest.java
public static Response POST(Request request, Object url, Map parameters, Map files) { List parts = new ArrayList(); for (String key : parameters.keySet()) { parts.add(new StringPart(key, parameters.get(key))); } for (String key : files.keySet()) { Part filePart; try { filePart = new FilePart(key, files.get(key)); } catch (FileNotFoundException e) { throw new RuntimeException(e); } parts.add(filePart); } MultipartRequestEntity requestEntity = new MultipartRequestEntity(parts.toArray(new Part[]{}), null); ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { requestEntity.writeRequest(baos); } catch (IOException e) { throw new RuntimeException(e); } InputStream body = new ByteArrayInputStream(baos.toByteArray()); String contentType = requestEntity.getContentType(); Http.Header header = new Http.Header(); header.name = "content-type"; header.values = Arrays.asList(new String[]{contentType}); request.headers.put("content-type", header); return POST(request, url, MULTIPART_FORM_DATA, body); }
在这个方法中,有一个new StringPart()的方法
parts.add(new StringPart(key, parameters.get(key)));
我跟进去之后,发现这厮也是重载方法: com.ning.http.multipart.StringPart.java
public StringPart(String name, String value, String charset) { super(name, "text/plain", charset != null ? charset : "US-ASCII", "8bit"); if(value == null) throw new IllegalArgumentException("Value may not be null"); if(value.indexOf('\0') != -1) { throw new IllegalArgumentException("NULs may not be present in string parts"); } else { this.value = value; return; } } public StringPart(String name, String value) { this(name, value, null); }
代码一目了然,
super(name, "text/plain", charset != null ? charset : "US-ASCII", "8bit");
如果没有charset,他就会默认“US-ASCII”! 问题出来的,解决方法就多了,可以在StringPart处将默认的改为“UTF-8”,也可以在POST方法中多传一个“UTF-8”参数。 但是,这两个方法都不太优雅,我这里提供一种方法。首先构造一个测试类的父类: function.BasisTest.java
public class BasisTest extends FunctionalTest{ public static Response POST(Object url, Map parameters) { return POST(newLocalRequest(), url, parameters, new HashMap()); } public static Request newLocalRequest() { Request request = Request.createRequest( null, "GET", "/", "", null, null, null, null, false, 80, "localhost", false, null, null ); request.encoding = "utf-8"; return request; } }
覆盖FunctionalTest的POST类,并构建自己的Request,这个地方还可以设定cookie,方便在有登陆拦截的情况下,进行功能测试。这里主要是设定请求的encoding。 然后在FunctionalTest中POST方法中将StringPart构造方法该为三个参数,加上request.encoding。
parts.add(new StringPart(key, parameters.get(key), request.encoding));
这样编码就是活的,可以自行设定。
{"box":[{"entityId":7,"id":7,"idea":"老马太瘦了","jPAContext":{"insideTransaction":true,"jPAConfig":{"configName":"play","enabled":true,"insideTransaction":true,"jPAContext":{"$ref":".."},"jpql":{}}},"persistent":false,"type":1},{"entityId":8,"id":8,"idea":"矮矬富","jPAContext":{"$ref":"$.box[0].jPAContext"},"persistent":false,"type":5},{"idea":"汝甚吊","jPAContext":{"$ref":"$.box[0].jPAContext"},"persistent":false,"type":3}],"code":"jack","entityId":1003,"id":1003,"ip":"192.168.1.122","jPAContext":{"$ref":"$.box[0].jPAContext"},"nick":"老马","passwd":"jack2","persistent":true,"qqmail":"[email protected]"}