2017-02-23 67 views
0

我正在参加一门软件测试课程,作为我的计算机科学选修课程的一部分。如何对以下方法进行单元测试

现在我们正在测试由研究生制作的软件,它不是很漂亮,我目前正在测试这个类有下面的方法,起初看起来很明显,它使用线程,它似乎是创建一个监听器来监听端口,有人可以向我解释这段代码在做什么?我将如何去测试这个功能?

public void startServer() throws IOException { 
    ServerSocket ss = new ServerSocket(portNum); 
    while(true) { 
    Socket s = ss.accept(); 
    Thread t = new Thread(new ConnectionHandler(s)); 
    t.start(); 
    } 
} 
+0

一个'while(true)'循环很难测试,因为测试永远不会结束(如果你不能在while(true)-loop内部调用一个exeption)。 ;-) –

+0

以防万一您觉得愿意接受我的回答;如果明天你可以考虑这样做会很好......因为我已经达到了日常上限;-) – GhostCat

回答

4

简而言之:该代码创建一个新的ServerSocket侦听特定端口上;和“请求”进入该端口时,它启动一个线程来处理该客户端。

与代码的问题:

  • 它运行一段时间(true)循环;所以方法是不是应该会回来的
  • 而且,除此之外,它写在很难测试的方式;基本上是因为你在那个方法中有两个对new的调用。

我将解释你是怎么克服的第二部分;然后让我们谈谈第一点。关于“测试”本身,您有两种选择:

  1. 锁定PowerMock(丑陋);或者Mockito间谍可能会帮助;到模拟那些调用新的。 (Mockito可以,但PowerMock并不在我眼里)
  2. 首选:将您的代码更改为易于测试;然后使用依赖注入。

像:

public class Server { 
    private final SocketFactory socketFactory; 
    private final ThreadFactory threadFactory; 

    public Server() { 
    this(new SocketFactory(), new ThreadFactory()); 
    } 

    Server(SocketFactory socketFactory, ... 
    this.socketFactory = socketFactory... 

public void startServer() throws IOException 
{ 
    ServerSocket ss = socketFactory.createSocketFor(portNum); 
    while(true) 
    { 
     Socket s = ss.accept(); 
     Thread t = threadFactory.newThreadFor(new ConnectionHandler(s)); 
     t.start(); 
    } 
} 

而现在......一切都超级简单:你可以使用第二包装保护的构造函数来插入嘲笑工厂;然后您可以配置/验证这些工厂看到您期望的呼叫。

当然,这可能看起来像“更多”的工作;因为现在你必须创建这两个其他类(实际上你可以使用接口IMPL类)。但事情是:你最终得到更好的设计,这不仅更容易测试,而且更容易维护和提高。

然后:创建“裸机”线程不再是一个好的做法。 (特别是不在while-true循环中;如果你还在搜索你的bug)你应该看看一些ThreadPool类;确保你是不是不断创建线程。那些是“昂贵的”;你应该非常喜欢“重用”线程。还有一些图书馆可以帮助你!

行,回到其他问题:截至目前,你根本无法合理 单位由于while(真)的测试此方法。你看,当你模拟那ServerSocket,那么调用accept()将不会阻塞;你遇到了一些无限循环,创建了模拟线程。因此:你必须重新编写这段代码(以允许在外部停止它)......或者你可以设置ThreadFactory模拟来返回一个嘲讽线程;或者你可以设置ThreadFactory模拟来返回一个模拟线程。抛出一些特定的异常。然后你的单元测试只是期望抛出异常 - 作为你预期的事情发生的间接“证明”。

+0

只是一个问题,关于实际的while循环,为什么这不会永远创建线程直到系统用完的资源?我注意到ConnectionHandler中的代码是作为单例实现的,这是否有所作为? –

+0

不是。这是因为accept()会阻塞,直到连接进来。所以,我的一半答案是错误的。尴尬。我将在今天晚些时候修复它,当我将手放在真正的键盘上时。 – GhostCat

+0

好的;更新了我的答案。如果你喜欢我的工作;随时upvote一些其他答案或我的问题;-) – GhostCat

1

这段代码的功能是监听端口。每次客户端连接时,都会将工作委托给新线程。这样服务器套接字就可以提供更多的请求。

测试连接处理机可以做,能,似乎有可能,连接处理器包含了最需要测试的代码。对于其余部分,您将不得不创建连接到此套接字的客户端线程,并且此时您正在编写的内容不是单元测试。类似这样的代码直接实例化类(而不是注入或传入实现接口的对象)使得很难替代mock。

我就打算编写单元测试,彻底覆盖连接处理,然后创建一个测试工具(一个独立的程序,你可以在其他JVM上运行)来创建线程连接到这一点。

相关问题