实验五 1 使用JUnit执行单元测试Word文档下载推荐.docx
《实验五 1 使用JUnit执行单元测试Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《实验五 1 使用JUnit执行单元测试Word文档下载推荐.docx(18页珍藏版)》请在冰豆网上搜索。
以下是对应的Java代码:
publicinterfaceRequest{
StringgetName();
}
publicinterfaceResponse{
publicinterfaceController{
ResponseprocessRequest(Requestrequest);
voidaddHandler(Requestrequest,RequestHandlerrequestHandler);
publicinterfaceRequestHandler{
Responseprocess(Requestrequest)throwsException;
下面是对接口的实现,DefaultController实现Controller接口,ErrorResponse实现了Response接口,大部分程序的后续工作就是对这个框架进行修补使其满足操作的需要。
具体实现代码如下:
importjava.util.HashMap;
importjava.util.Map;
publicclassDefaultControllerimplementsController{
privateMaprequestHandlers=newHashMap();
protectedRequestHandlergetHandler(Requestrequest){
if(!
this.requestHandlers.containsKey(request.getName())){
Stringmessage="
Cannotfindhandlerforrequestname"
+"
["
+request.getName()+"
]"
;
thrownewRuntimeException(message);
}
return(RequestHandler)this.requestHandlers.get(request.getName());
}
publicResponseprocessRequest(Requestrequest){
Responseresponse;
try{
response=getHandler(request).process(request);
}catch(Exceptionexception){
response=newErrorResponse(request,exception);
returnresponse;
publicvoidaddHandler(Requestrequest,RequestHandlerrequestHandler){
if(this.requestHandlers.containsKey(request.getName())){
thrownewRuntimeException("
Arequesthandlerhas"
+"
alreadybeenregisteredforrequestname"
);
}else{
this.requestHandlers.put(request.getName(),requestHandler);
publicclassErrorResponseimplementsResponse{
privateRequestoriginalRequest;
privateExceptionoriginalException;
publicErrorResponse(Requestrequest,Exceptionexception){
this.originalRequest=request;
this.originalException=exception;
publicRequestgetOriginalRequest(){
returnthis.originalRequest;
publicExceptiongetOriginalException(){
returnthis.originalException;
最终程序组织为:
下面使用JUnit来测试这个Controller是否正常工作。
在eclipse中新建项目,导入或输入上面的代码。
新建一个test源代码文件夹,将所有的测试代码都放在这个文件夹中。
新建一个JUnitTestCase,测试DefaultController类,命名为TestDefaultController1。
内容如下:
Next进入下一步,选择要测试的方法:
自动生成的代码如下:
importjunit.framework.TestCase;
publicclassTestDefalutController1extendsTestCase{
protectedvoidsetUp()throwsException{
super.setUp();
protectedvoidtearDown()throwsException{
super.tearDown();
publicfinalvoidtestAddHandler(){
fail("
Notyetimplemented"
}
添加代码,使其成为第一个测试类,具体代码参考如下:
privateControllercontroller;
controller=newDefaultController();
点击RunRunAsJUnitTest,则得到失败的结果,因为现在还没有实现测试的逻辑。
下面开始实现测试的代码,第一个碰到的问题就是,用到的测试类(脚手架之类的东西)如何组织。
一种方案将这些类放在测试用例类中作为内部类;
一种方案将其作为作为共有类。
原则是:
如果类比较简单,而且以后也不太可能变复杂,则将其写成内部类比较简单方便,否则将其作为外部的公共类。
此处我们将其写为内部类。
用到的测试相关的类有Request实现类,Response实现类,RequestHandler实现类。
结构如图:
具体代码如下,注意阴影段落中为新建的测试类:
publicclassTestDefaultController2extendsTestCase{
privateDefaultControllercontroller;
privateclassTestRequestimplementsRequest{
publicStringgetName(){
return"
Test"
privateclassTestHandlerimplementsRequestHandler{
publicResponseprocess(Requestrequest)throwsException{
returnnewTestResponse();
privateclassTestResponseimplementsResponse{
//empty
publicvoidtestAddHandler(){
Requestrequest=newTestRequest();
RequestHandlerhandler=newTestHandler();
controller.addHandler(request,handler);
RequestHandlerhandler2=controller.getHandler(request);
assertSame(handler2,handler);
publicvoidtestProcessRequest(){
Responseresponse=controller.processRequest(request);
assertNotNull("
Mustnotreturnanullresponse"
response);
assertEquals(TestResponse.class,response.getClass());
点击RunRunAsJUnitTest,运行结果如下:
说明测试成功。
重点关注assert方法的使用。
注意蓝色底纹的代码,在两段中属于重复的代码,对于各个测试中重复的设置等操作可以将其抽出放入setUp中。
这样可以改善代码的设计。
因此改进的下一个版本如下:
publicclassTestDefaultController3extendsTestCase{
privateRequestrequest;
privateRequestHandlerhandler;
request=newTestRequest();
handler=newTestHandler();
上面的测试中对TestResponse的检查停留在类的比较上,我们希望能对返回的响应中的内容进行判断,因此对TestResponse类进行改进,增加一个内容,简单表示返回的值:
重构后的TestResponse类如下:
privatestaticfinalStringNAME="
returnNAME;
publicbooleanequals(Objectobject){
booleanresult=false;
if(objectinstanceofTestResponse){
result=((TestResponse)object).getName().equals(getName());
}
returnresult;
publicinthashCode(){
returnNAME.hashCode();
测试的逻辑中可以改为:
assertEquals(newTestResponse(),response);
到目前为止,测试都没有偏离执行的主路径。
如果待测对象之一的行为已未预期的方式发生了改变,如发生了异常,因此这类问题也需要检测。
模拟异常条件
异常testcase是单元测试的真正闪光之处。
单元测试可以模拟异常条件,而不是坐等异常的发生(如集成测试中)。
本例中在processRequest方法中已经有了先见之明,将发生错误的情况封装成一个ErrorResponse返回作为特殊的响应。
但是是否可能发生其他异常情况呢?
这里我们需要更多的考虑。
try{
如何模拟异常条件以测试处理器是否正常工作呢?
为了测试正常请求处理,创建了TestRequestHandler,处理器返回TestRequest。
为了测试异常错误处理,创建一个TestExceptionHandler,这个处理器抛出一个异常。
privateclassTestExceptionHandlerimplementsRequestHandler{
thrownewException("
errorprocessingrequest"
下面创建一个测试方法,注册这个处理器,并试图处理一个请求,如下:
publicvoidtestProcessRequestAnswersErrorResponse(){
TestRequestrequest=newTestRequest();
TestExceptionHandlerhandler=newTestExceptionHandler();
assertEquals(ErrorResponse.class,response.getClass());
上面测试中的代码与setUp中的很类似,与之前的代码一起运行时会发生问题。
即注册一个重名的请求,会抛出未声明的RuntimeException。
因此我们设计两个方法来检测这一类问题:
其中fail表示如果没有发生异常,则这个测试失败。
没有达到检测的目的。
这条语句防止异常没有发生。
捕获异常时,说明其名称为expected,表明这是成功的测试,因此异常处理中使用assertTrue(true)。
publicvoidtestGetHandlerNotDefined(){
TestRequestrequest=newTestRequest("
testNotDefined"
controller.getHandler(request);
fail("
Anexceptionshouldberaisediftherequested"
handlerhasnotbeenregistered"
}catch(RuntimeExceptionexpected){
assertTrue(true);
publicvoidtestAddRequestDuplicateName(){
TestHandlerhandler=newTestHandler();
controller.addHandler(request,handler);
Anexceptionshouldberaisedifthedefault"
TestRequesthasalreadybeenregistered"
基于这样的考虑,对TestRequest进行重新设计,使其能处理更一般的情况。
即创建不同的请求。
privatestaticfinalStringDEFAULT_NAME="
privateStringname;
publicTestRequest(Stringname){
this.name=name;
publicTestRequest(){
this(DEFAULT_NAME);
returnthis.name;
最终所有的测试代码如下:
publicclassTestDefaultControllerextendsTestCase{
returnthis.name