背景:
在进行web自动化测试过程中(eg. Selenium),测试代码和Application代码是分开的。也就是说,自动化测试的代码中是不能调用Application的代码。只是在test case运行时,利用application的web容器。
这样就会遇到一个问题,Application中的某些功能,需要后台service执行后才能获得数据,这些service一般是定时执行的。在自动化测试中,比如click页面上的某些按钮,要想在页面上看到数据,需要等待service执行以后,才能看到数据。有些service的执行周期可能是24小时。显然不能让test case等待24小时后再检查数据。
解决方案:
针对上述问题,很容易想到的解决办法,就是在test case执行过程中,显式地调用application的后台service。前面提到过,test代码是不能调用application的代码。那该怎么办呢?
一个通用的解决办法是,把application的service功能封装成标准的接口,比如 web service,REST等,对外开放。然后在test中调用这些标准的web service或REST接口。这样就解决了依赖的问题。
具体实现:
这里以REST为例,介绍把application后台service封装成RESTFul接口的方法。在实际的开发过程中,会有很多后台service。随着系统的升级,可能还会增加新的service。如果每增加一个service,都开放一个RESTful接口,就会是系统变得越来越笨重。而且有些开发是plugin的形式,也不允许新增Restful接口。
这就需要在系统设计的时候,考虑到这一点。怎么办呢?在Application core中定义一个RESTful接口对外开放。在这个开放的接口中进行内部处理。方法是,定义一个可扩展的REST Service接口,通过JDK的java.util.ServiceLoader来加载实现该REST Service接口的具体类。根据URL中指定的serviceName来触发相应的REST Service。
以Apache Wink Framework为例,介绍部署RESTful API的方法
--------------------------Application core中的RESTful接口------------------------------------------------------
package com.mycompany.rest;
@Path("/automation/AutomationServiceTest")
public class TestingRestfulResource {
private static Map<String, AutomationServiceTest> serviceTestMap =
new HashMap<String, AutomationServiceTest>();
static {
ServiceLoader<AutomationServiceTest> driverProvider =
ServiceLoader.load(AutomationServiceTest.class);
for (AutomationServiceTestserviceTest : driverProvider) {
serviceTestMap.put(serviceTest.getServiceName(), serviceTest);
}
}
@GET
@Produces({MediaType.TEXT_PLAIN, MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Object runService(@Context final HttpServletRequest request)
throws WSException
{
// The service name like "AgileSyncService"
String serviceName = request.getParameter("serviceName");
AutomationServiceTest serviceTest = serviceTestMap.get(serviceName);
if (null == serviceTest) {
log.error("Service " + serviceName + "not found");
throw new WSException(Response.Status.INTERNAL_SERVER_ERROR, request,
WSErrorHelper
.createWSError("INT_SERVICE_NOT_FOUND", new String[] {serviceName}));
}
return serviceTest.runService(request);
}
}
在wink_ws.app文件中增加一行
com.mycompany.rest.TestingRestfulResource
-------------------------AutomationServiceTest 接口-------------------------------------
package com.mycompany.test.plugin.rest.service;
import javax.servlet.ServletRequest;
public interface AutomationServiceTest {
public Object runService(ServletRequest request);
public String getServiceName();
}
----------------------RESTful service实现类--------------------------------------------
package com.mycompany.test.plugin.rest.service.impl
public class MyServiceTestImpl implements AutomationServiceTest {
@Override
public Object runService(ServletRequest request) {
MyService service = new MyService ();
service.runService("jobID", 2L, 2L);
return "<result>run my service successfully</result>";
}
@Override
public String getServiceName() {
return "MyService";
}
}
在/META-INF/services/com.mycompany.test.plugin.rest.service.AutomationServiceTest 文件中增加一行
com.mycompany.test.plugin.rest.service.impl.MyServiceTestImpl
-------------------------------------------------------------------------------------------------------------------
这样,通过URL:
http://localhost:8080/<my app>/rest/automation/AutomationServiceTest?serviceName=MyService
就可以在Automation Testing的代码中调用RESTful接口,进而触发后台servie。
比如,利用Cactus framework,可以按照如下方式编写testing code。
package com.mycompany.webdriver.page.service;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.HttpParams;
import org.junit.Before;
import org.junit.Test;
public class TestMyServic {
private static final String SERVICE_URL = "http://localhost:8080/app/rest/automation/AutomationServiceTest?serviceName=MyService";
private DefaultHttpClient client;
private HttpGet get;
@Before
public void setup() {
//For REST API Call
client = new DefaultHttpClient();
//set time out
HttpParams params = new BasicHttpParams();
params.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 6000);
client.setParams(params);
get = new HttpGet();
}
@Test
public void testCallService() {
System.out.println("begin............");
get.setURI(URI.create(SERVICE_URL));
HttpResponse response;
try {
response = client.execute(get);
String responseText = getHttpResponseBodyContent(response);
System.out.println("******response: " + responseText);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("end............");
}
private static String getHttpResponseBodyContent(HttpResponse response) throws IllegalStateException, IOException{
String result = null;
BufferedReader bufferedReader = null;
try{
bufferedReader = new BufferedReader(
new InputStreamReader((response.getEntity().getContent())));
StringBuilder sb = new StringBuilder();
String outputLine;
while ((outputLine = bufferedReader.readLine()) != null) {
sb.append(outputLine);
}
result = sb.toString();
}finally{
bufferedReader.close();
}
return result;
}
}