Url接口测试:HttpClient模拟登录效果

来源:互联网 发布:mkv播放器 for mac 编辑:程序博客网 时间:2024/05/17 22:29

最近做的一个需求,用JUnit做业务测试,需要模拟用户登录,尝试了几种方法,总结一下。
HttpUrlConnection(不可行)
SpringFramework.test(部分可行)
HttpClient(可行)


(一)HttpUrlConnection

一开始很自然想到用HttpUrlConnection模拟登录。

public class RequestTest{        private String SessionId;        @Test        public void test1() throws Exception{            login(user, psw); // login.            String result = post(url, [{...},{...}]) // do test.        }        public void longin(String user, String psw) throws Exception{            String strUrl = "...";            Url url = new Url(strUrl);            HttpURLConnection conn = (HttpURLConnection) url.openConnection();            conn.setRequestMethod("POST");            ... // set other params;            conn.setDoInput(true);            conn.setDoOutput(true);            conn.connect();            String cookie = conn.getHeaderField("Set-Cookie");            SessionId = ((cookie.split(";"))[0].split("="))[1];            System.out.println("SessionId = " + SessionId);        }        public String post(String strUrl, String jsonParams) throws Exception{            String result = "";            BufferedReader in = null;            PrintWriter out = null;            try{                URL url = new Url(strUrl);                HttpURLConnection conn = (HttpURLConnection) url.openConnection();                conn.setRequestMethod("POST");                ... // set other params;                conn.setDoInput(true);                conn.setDoOutput(true);                conn.setRequestProperty("Cookie", "SessionId=" + SessionId); // set cookie.                conn.connect();                out = new PrintWriter(conn.getOutputStream());                out.print(jsonParams);                out.flush();                in = new BufferedReader(new InputStreamReader(conn.getInputStream()));                String line = null;                while((line = in.readLine()) != null){                    result = result + line;                }            }catch(Exception e){                throw e;            }finally{                ... // close stream.                retrun result;            }        }    }

这里的关键在于登录时通过“Set-Cookie”响应头获取SessionId,然后在后续测试时发送该SessionId到服务器以验证登录权限。但是,实际操作之后发现没有效果,原因在于登录通过之后,由于实际上是没有浏览器在连接的,所以服务器的安全系统认为“浏览器已经关闭”了,所以立即将Session销毁,SessionId失效。于是尝试第二种方法:SpringFramework的测试包。

(二)SpringFramework.test

这实际上是一个偷懒的做法,绕开url请求,通过注解技术直接调用Controller里面相应url所映射的方法。

@ContextConfiguration(locations = {"classpath:mvc-dispatcher-servlet.xml"})    @RunWith(SpringJUnit4ClassRunner.class)    public class RequestTest{        @Autowired        public TestController controller;        @Test        public void test1(){            controller.test()... // do test.        }    }

这种方法逻辑比较简单,代码也少,需要注意的是相关的controller、dao等对象需要通过@Autowired注解创建,不能new。
这种方法在大部分情况下是可行的,包括部分需要登录权限的地方也可以通过验证。但是,当测试到一个方法需要从Session中获取当前登录user的时候,由于没有实际登录,所以获取的user为null,产生了NullPointerException。于是乎,再尝试第三种方法:Apache的HttpClient。

(三)HttpClient

Apache的HttpClient包,测试url接口的神器,经测试可以完美模拟浏览器登录效果。

public class RequestTest{        private static CloseableHttpClient client;        @Autowired        public TestController controller;        @BeforeClass        public static void beforeClass(){            login(user, psw, loginUrl);        }        @AfterClass        public static void beforeClass(){            logout(logoutUrl);        }        @Test        public void test1(){            post(url1);            get(url2);            ... // do test.        }        private static boolean login(String user, String psw, String loginUrl){            client = HttpClientBuilder.create().build();            HttpPost post = new HttpPost(loginUrl);            HttpEntity loginEntity;            try{                loginEntity = new UrlEncodedFormEntity(Arrays.asList(new NameValuePair[]{                    new BasicNameValuePair("user", user),                    new BasicNameValuePair("psw", psw),                    }));                post.setEntity(loginEntity);                CloseableHttpResponse response = client.execute(post);                StatusLine status = response.getStatusLine();                if(status.getStatusCode() == 200){                    return true;                }            }catch(Exception e){                return false;            }            return false;        }        private static void logout(String logoutUrl){            HttpGet get = new HttpGet(logoutUrl);            try{                CloseableHttpResponse response = client.execute(get);            }catch{            }        }        private String post(String url, Map<String, Object> params) throw ClientProtocolException, IOException{            HttpPost post = new HttpPost(url);            post.setHeadr("Content-type", "application/json"); // send json message to server.            post.setHeadr("Accept", "application/json"); // receive json message from server.            ... // set headers and params.            String strParams = new ObjectMapper().writeValueAsString(params);            post.setEntity(new StringEntity(strParams));             CloseableHttpResponse response = client.execute(post);            if(200 == response.getStatusLine().getStatusCode()){                InputStream in = response.getEntity().getContent();                String result = toString(in) // use other API to get String from the input stream.                return result;            }            return null;        }        private String get(String url) throw ClientProtocolException, IOException{            HttpGet get = new HttpGet(url);            ... // set headers and params.            CloseableHttpResponse response = client.execute(get);                    if(200 == response.getStatusLine().getStatusCode()){                InputStream in = response.getEntity().getContent();                String result = toString(in) // use other API to get String from the input stream.                return result;            }            return null;        }    }

模拟过程:创建一个CloseableHttpClient类型的成员变量client,用client给服务器发送登录请求,登录通过后就模拟了一个“保持连接状态的浏览器”,然后就可以通过client给服务器发送各种请求,效果和通过浏览器发送请求相同。

还有一点需要注意:由于“浏览器”是一直“连着”的,意味着用户一直处于登录状态(直至Session失效),在服务器安全系统拒绝重复登录的情况下,同一用户不能再次登录。有时候我们可能需要短时间内重复跑多次测试,在这种情况下,最好完成测试后主动退出。

原创粉丝点击