Servlet单元测试
单元测试servlet可能有些棘手。之所以棘手,是因为servlet依赖于servlet容器和几个servlet容器接口。为了正确地测试servlet,我们或者必须在真实的servlet容器中运行它,或者创建一个可以通过代码在单元测试期间激活的模拟servlet容器。无论哪种方式,正确设置都需要一些工作。
我通常要做的是"将代码移出边界类",正如我在"可测试性设计"一文中所述。基本上,如果可能的话,我将尝试将Servlet中的主要业务逻辑推入一个独立于Servlet API的独立类中。
首先,让我们看一个非常简单的servlet:
public class MyServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String string1 = request.getParameter("string1"); String string2 = request.getParameter("string2"); String string3 = request.getParameter("string3"); String concatenated = string1 + "," + string2 + "," + string3; response.getWriter().write(concatenated); response.getWriter().flush(); } }
该Servlet仅从请求中获取3个参数,将它们连接成一个字符串(逗号分隔),然后将响应写回到浏览器。它不是一个非常有用的servlet,但是我一直非常简单地使它易于理解我在说什么。
真正的业务逻辑实际上仅由串联逻辑组成。剩下的就是我所谓的"调度"逻辑或者"边界"逻辑。因此,我将采用串联逻辑并进入一个单独的类,该类可以独立于MyServlet类进行测试。
这是重新设计的servlet。该代码实际上看起来并不比以前的servlet小很多,但是请记住,这是一个非常简单的示例。更改后的代码以粗体标记。
public class MyServlet extends HttpServlet { protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String string1 = request.getParameter("string1"); String string2 = request.getParameter("string2"); String string3 = request.getParameter("string3"); String concatenated = MyConcatenator.concatenate( string1, string2, string3); response.getWriter().write(concatenated); response.getWriter().flush(); } }
注意串联逻辑如何被移动到名为MyConcatenator的类。 servlet剩下的唯一事情就是边界逻辑,即从请求对象中取出请求参数,并将连接后的字符串写回到响应对象中。这种边界逻辑非常简单,并且项目可能不需要自动进行单元测试就可以生存。
这是MyConcatenator类的样子。是的,这很简单,但是再次,这是因为我选择了一个非常简单的大小写连接字符串的情况。如果是图像生成,那将更加复杂。这是代码:
public class MyConcatenator { public static String concatenate(String ... strings){ StringBuilder builder = new StringBuilder(); for(int i = 0; i<strings.length; i++){ if(i>0){ builder.append(","); } builder.append(strings[i]); } return builder.toString(); } }
注意,concatenate()方法是如何仅引用字符串数组的。没有引用servlet特定的接口。这使得为MyConcatenator分别编写单元测试变得非常容易。这是这样的单元测试:
import org.junit.Test; import static junit.framework.Assert.*; public class MyConcatenatorTest { @Test public void testConcatenate(){ String concatenated = MyConcatenator.concatenate( "one", "two", "three", "four"); assertEquals("one,two,three,four", concatenated); } }
再次注意,在此单元测试中,没有必要引用任何servlet类或者接口。