如何对以下方法进行单元测试
How to Unit test the following method
我正在选修软件测试课程作为计算机科学选修课的一部分。
现在正在测试研究生做的软件,不是很漂亮,有这个class我目前正在测试有下面这个方法,乍一看好像是用线程似乎正在创建一个侦听器来侦听端口,有人可以解释一下这段代码在做什么吗?我将如何测试此功能?
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();
}
}
这段代码的作用是监听一个端口。每次客户端连接时,它都会将工作委托给一个新线程。这样服务器套接字就可以为更多请求提供服务。
测试连接处理程序可能可行,连接处理程序似乎包含最需要测试的代码。对于其余部分,您将必须创建连接到此套接字的客户端线程,此时您正在编写的不是单元测试。像这样直接实例化 类 的代码(而不是注入或传入实现接口的对象)使得很难替代模拟。
我打算编写单元测试来彻底覆盖连接处理程序,然后创建一个测试工具(一个单独的程序,你可以 运行 在另一个 jvm 中)创建线程来连接到这个。
简而言之:代码创建了一个新的ServerSocket来监听特定的端口; 当一个"request"进入该端口时,它会启动一个线程来处理该客户端。
该代码的问题:
- 它运行一个 while(true) 循环;所以那个方法不是应该永远回来
- 除此之外,它的编写方式难以测试;基本上是因为您在该方法中对
new
进行了两次调用。
我会解释你如何克服第二部分;然后让我们谈谈第一点。关于 "testing" 本身,你有两个选择:
- 锁定PowerMock(丑);或者 Mockito 间谍可以提供帮助; mock 那些对 new 的调用。 (Mockito还行,但PowerMock在我眼里没那么多)
- 首选:更改您的代码以便于测试;然后使用依赖注入。
赞:
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();
}
}
现在……一切都超级简单:您可以使用第二个受包保护的构造函数来插入 模拟工厂;然后您可以 configure/verify 这些工厂看到您期望的电话。
当然,这看起来 "more" 可行;现在你必须创建另外两个 classes(实际上你可以使用 interfaces 加上 impl classes ).但事实是:你最终会得到一个更好的设计,它不仅更容易测试,而且更容易维护和增强。
然后:创建 "bare metal" 线程不再是一个好的做法。 (尤其不是在 while-true 循环中;以防您仍在搜索您的错误)您应该查看一些 ThreadPool class;以确保您 而不是 不断创建 new 线程。那些是 "expensive";您应该非常喜欢 "re-use" 线程。还有一些图书馆可以提供帮助!
好的,回到另一个问题:到目前为止,你根本无法理解
unit 由于 while(true) 而测试此方法。您会看到,当您 mock 那个 ServerSocket 时,对 accept() 的调用将不会阻塞;然后你 运行 进入了一些创建模拟线程的无限循环。
所以:您要么必须重新编写此代码(以允许在外部停止它)...或者您可以将 ThreadFactory mock 设置为 return a mocked线;抛出一些特定的异常。然后你的单元测试只是期望抛出异常 - 间接 "proof" 你所期望的事情确实发生了。
我正在选修软件测试课程作为计算机科学选修课的一部分。
现在正在测试研究生做的软件,不是很漂亮,有这个class我目前正在测试有下面这个方法,乍一看好像是用线程似乎正在创建一个侦听器来侦听端口,有人可以解释一下这段代码在做什么吗?我将如何测试此功能?
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();
}
}
这段代码的作用是监听一个端口。每次客户端连接时,它都会将工作委托给一个新线程。这样服务器套接字就可以为更多请求提供服务。
测试连接处理程序可能可行,连接处理程序似乎包含最需要测试的代码。对于其余部分,您将必须创建连接到此套接字的客户端线程,此时您正在编写的不是单元测试。像这样直接实例化 类 的代码(而不是注入或传入实现接口的对象)使得很难替代模拟。
我打算编写单元测试来彻底覆盖连接处理程序,然后创建一个测试工具(一个单独的程序,你可以 运行 在另一个 jvm 中)创建线程来连接到这个。
简而言之:代码创建了一个新的ServerSocket来监听特定的端口; 当一个"request"进入该端口时,它会启动一个线程来处理该客户端。
该代码的问题:
- 它运行一个 while(true) 循环;所以那个方法不是应该永远回来
- 除此之外,它的编写方式难以测试;基本上是因为您在该方法中对
new
进行了两次调用。
我会解释你如何克服第二部分;然后让我们谈谈第一点。关于 "testing" 本身,你有两个选择:
- 锁定PowerMock(丑);或者 Mockito 间谍可以提供帮助; mock 那些对 new 的调用。 (Mockito还行,但PowerMock在我眼里没那么多)
- 首选:更改您的代码以便于测试;然后使用依赖注入。
赞:
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();
}
}
现在……一切都超级简单:您可以使用第二个受包保护的构造函数来插入 模拟工厂;然后您可以 configure/verify 这些工厂看到您期望的电话。
当然,这看起来 "more" 可行;现在你必须创建另外两个 classes(实际上你可以使用 interfaces 加上 impl classes ).但事实是:你最终会得到一个更好的设计,它不仅更容易测试,而且更容易维护和增强。
然后:创建 "bare metal" 线程不再是一个好的做法。 (尤其不是在 while-true 循环中;以防您仍在搜索您的错误)您应该查看一些 ThreadPool class;以确保您 而不是 不断创建 new 线程。那些是 "expensive";您应该非常喜欢 "re-use" 线程。还有一些图书馆可以提供帮助!
好的,回到另一个问题:到目前为止,你根本无法理解 unit 由于 while(true) 而测试此方法。您会看到,当您 mock 那个 ServerSocket 时,对 accept() 的调用将不会阻塞;然后你 运行 进入了一些创建模拟线程的无限循环。
所以:您要么必须重新编写此代码(以允许在外部停止它)...或者您可以将 ThreadFactory mock 设置为 return a mocked线;抛出一些特定的异常。然后你的单元测试只是期望抛出异常 - 间接 "proof" 你所期望的事情确实发生了。