1.Controller.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
/**
* A controller interface.
*
* @version $Id: Controller.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
public interface Controller
{
//定义一个用来处理收到的请求的方法。
Response processRequest( Request request );
//这是个非常重要的设计元素,addHadndler方法允许扩展Controller而不必修改Java源代码。
void addHandler( Request request, RequestHandler requestHandler );
}
2.DefaultController.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
import java.util.HashMap;
import java.util.Map;
/**
* Default implementation of the controller.
*
* @version $Id: DefaultController.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
public class DefaultController implements Controller {
//声明一个HashMap,用作请求处理器的注册表;
private Map<String, RequestHandler> requestHandlers = new HashMap<String, RequestHandler>();
//增加一个保护方法getHandler,用来为指定的请求获取HequestHandler.
protected RequestHandler getHandler(Request request) {
/*如果RequestHandler没有注册,那么抛出RuntimeException异常,
* 因为一个意外事件意味着编程错误,而不是由用户或者外界引起的
* 错误.Java并没有要求你在方法签名中说明RuntimeException,
* 但依然可以捕获这个异常。*/
if (!this.requestHandlers.containsKey(request.getName())) {
String message = "Cannot find handler for request name " + "["
+ request.getName() + "]";
throw new RuntimeException(message);
}
//返回选择的处理器
return this.requestHandlers.get(request.getName());
}
/*把请求分派到合适的处理器,并且把处理器的Response传回给调用者,
* 如果出现了异常,那么ErrorResponse会捕获它*/
public Response processRequest(Request request) {//接受请求
Response response;
try {
response = getHandler(request).process(request);//路由请求
} catch (Exception exception) {
response = new ErrorResponse(request, exception);//错误处理:子类化 ErrorResponse
}
//返回适当的处理器来调用。
return response;
}
public void addHandler(Request request, RequestHandler requestHandler) {
if (this.requestHandlers.containsKey(request.getName())) {
//检查处理器的名字是否已经注册过了,若已经注册过了,抛出异常。
throw new RuntimeException("A request handler has "
+ "already been registered for request name " + "["
+ request.getName() + "]");
} else {
this.requestHandlers.put(request.getName(), requestHandler);
}
}
}
3.Request.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
/**
* The request interface.
*
* @version $Id: Request.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
//初步的接口:返回一个请求的名称,以便区分不同的请求。
public interface Request
{
String getName();
}
4.RequestHandler.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
/**
* The request-handler interface.
*
* @version $Id: RequestHandler.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
/*定义一个能处理一个request并返回Response的反应RequestHandler。
RequestHandler是一个辅助性组件,设计来做最“肮脏”的工作。
它调用可能会抛出任何类型异常的类。*/
public interface RequestHandler
{
Response process( Request request ) throws Exception;
}
5.Response.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
/**
* The response interface.
*
* @version $Id: Response.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
//Response对象封装的是稍后可以处理的东西,目前只要满足签名就可以了。
public interface Response
{
}
6.ErrorResponse.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
/**
* Response that is returned in case of an error.
*
* @version $Id: ErrorResponse.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
public class ErrorResponse
implements Response
{
private Request originalRequest;
private Exception originalException;
public ErrorResponse( Request request, Exception exception )
{
this.originalRequest = request;
this.originalException = exception;
}
public Request getOriginalRequest()
{
return this.originalRequest;
}
public Exception getOriginalException()
{
return this.originalException;
}
}
7.TestDefaultController.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
/**
* Test-case for the default controller.
*
* @version $Id: TestDefaultController.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
//controller(控制器):同用户交互,控制并管理每个请求的处理。
/*controller主要做这些事:
接受请求
对请求执行常用计算
选择合适的请求处理器
路由请求,以便处理器可以执行相关的业务逻辑。
可能会提供一个顶层的处理器用于处理错误和异常*/
//Request ,Response, RequestHandler Controller 他们的关系是:Controller授受Request,分发给RquestHandler,并返回Response
/*添加handler
添加一个RequestHandler,引用一个Request.
获得到一个RequestHandler,传递的是同一个Request.
检查看是得到RequestHandler,是否就是添加的那一个。*/
public class TestDefaultController
{
private DefaultController controller;
private Request request;
private RequestHandler handler;
@Before
public void initialize()
throws Exception
{
controller = new DefaultController();// 实例化对象
request = new SampleRequest();; // 实例化对象
handler = new SampleHandler(); // 实例化对象
// 下面是的代码是测试目标:controller( 待测对象)添加一个测试handler,
controller.addHandler( request, handler );
}
@Test
public void testAddHandler()// 为测试启一个名字
{
// 把Handler读回到新的变量中。
RequestHandler handler2 = controller.getHandler( request );
// 对比两个对象是否是同一个对象。
assertSame( "Controller.getHandler must return the samplehandler", handler2, handler );
}
//controller的核心功能--处理请求
@Test
public void testProcessRequest()
{
Response response = controller.processRequest( request );
assertNotNull( "Must not return a null response", response );
assertEquals( "", new SampleResponse(), response );
}
//测试异常
//下面创建一个测试方法,注册这个Handler,并试图处理一个请求
@Test
public void testProcessRequestAnswersErrorResponse()
{
//TestRequest request =new TestRequest();异常请求会和fixture冲突
SampleRequest request = new SampleRequest( "testError" );
SampleExceptionHandler handler = new SampleExceptionHandler();
//创建测试对象并添加测试处理器
controller.addHandler( request, handler );
Response response = controller.processRequest( request );
assertNotNull( "Must not return a null response", response );
assertEquals( ErrorResponse.class, response.getClass() );
}
//测试抛出异常的方法
@Test( expected = RuntimeException.class )
public void testGetHandlerNotDefined()
{
SampleRequest request = new SampleRequest( "testNotDefined" );
controller.getHandler( request );
}
//测试抛出异常的方法
@Test( expected = RuntimeException.class )
public void testAddRequestDuplicateName()
{
SampleRequest request = new SampleRequest();
SampleHandler handler = new SampleHandler();
controller.addHandler( request, handler );
}
//测试超时
@Test( timeout = 130 )
@Ignore( value = "Skip for now" )
public void testProcessMultipleRequestsTimeout()
{
Request request;
Response response = new SampleResponse();
RequestHandler handler = new SampleHandler();
for ( int i = 0; i < 99999; i++ )
{
request = new SampleRequest( String.valueOf( i ) );
controller.addHandler( request, handler );
response = controller.processRequest( request );
assertNotNull( response );
assertNotSame( ErrorResponse.class, response.getClass() );
}
}
//改进了的TestRequest,更名为SampleRequest
//SampleRequest可以以不同的名字实例化。
private class SampleRequest
implements Request
{
private static final String DEFAULT_NAME = "Test";
private String name;
public SampleRequest( String name )
{
this.name = name;
}
public SampleRequest()
{
this( DEFAULT_NAME );
}
public String getName()
{
return this.name;
}
}
private class SampleExceptionHandler
implements RequestHandler
{
public Response process( Request request )
throws Exception
{
throw new Exception( "error processing request" );
}
}
private class SampleResponse
implements Response
{
private static final String DEFAULT_NAME = "Test";
private String name;
public String getName()
{
return this.name;
}
public SampleResponse( String name )
{
this.name = name;
}
public SampleResponse()
{
this( DEFAULT_NAME );
}
public boolean equals( Object object )
{
boolean result = false;
if ( object instanceof SampleResponse )
{
result = ( (SampleResponse) object ).getName().equals( getName() );
}
return result;
}
public int hashCode()
{
return this.name.hashCode();
}
}
private class SampleHandler
implements RequestHandler
{
public Response process( Request request )
throws Exception
{
return new SampleResponse();
}
}
}
结果图:
8.HamcrestTest.java:
/*
* ========================================================================
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ========================================================================
*/
package com.manning.junitbook.ch03.mastering;
import static org.junit.Assert.assertTrue;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.assertThat;
import static org.hamcrest.CoreMatchers.anyOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.matchers.JUnitMatchers.hasItem;
/**
* A sample hamcrest test.
*
* @version $Id: HamcrestTest.java 553 2010-03-06 12:29:58Z paranoid12 $
*/
public class HamcrestTest {
private List<String> values;
@Before //为测试初始化一些数据
public void setUpList() {
values = new ArrayList<String>();
values.add("x");
values.add("y");
values.add("z");
}
@Test
public void testWithoutHamcrest() { //没有使用Hamcrest的测试
assertTrue(values.contains("one") || values.contains("two")
|| values.contains("three")); //断言条件为真
}
@Test
public void testWithHamcrest() { //使用Hamcrest的测试
assertThat(values, hasItem(anyOf(equalTo("one"), equalTo("two"),
equalTo("three")))); //好处是有栈跟踪消息
}
}
结果图: