我正在开发一个新项目。这是迄今为止所做的:
我想做的下一件事是从骨架(高级方法)到嵌套对象实现方法。不过,我想在编写实现之前为每个方法创建一个单元测试。首先实现高级方法不会有任何问题,因为我将使用接口并仅使用DI在外部Java配置文件中绑定具体实现。
我要实现的第一种方法称为lookForChanges()
,它接受并返回void。这个方法由Spring的调度程序(@Scheduled)调用,它管理整个过程:它从数据库中检索数据,从Web服务检索数据,比较它们,如果有任何更改,则更新数据库并将JMS消息发送到客户端。当然,它并不是自己做所有这些事情,而是调用相关的类和方法。
所以我遇到的第一个问题是如何为void方法创建单元测试。在所有教程中,测试方法始终接受参数并返回结果。我找到了in this question的答案。他说即使没有检查结果,至少有一个可以确保调用测试方法中的方法并且参数的顺序正确。
我有点喜欢这个答案,但问题是我正在使用TDD所以对于提出这个问题的人来说,我在实施测试方法之前写了测试,所以我不喜欢#39;不知道它将使用哪些方法和顺序。我可以猜测,但只有在方法已经实施后我才会确定。
那么,在实现之前如何测试void skeleton方法呢?
答案 0 :(得分:4)
所以我遇到的第一个问题是如何为void方法创建单元测试。
void方法意味着协作者。你验证了那些。
实施例。假设我们需要一个将System.in
复制到System.out
的任务。我们如何为此编写自动化测试?
void copy() {
// Does something clever with System.in and System.out
}
但如果你稍微眯一下,你会发现你的代码看起来很像
void copy() {
InputStream in = System.in;
PrintStream out = System.out;
// Does something clever with `in` and `out`
}
如果我们对此执行并提取方法重构,那么我们最终可能会得到类似
的代码void copy() {
InputStream in = System.in;
PrintStream out = System.out;
copy(in, out);
}
void copy(InputStream in, PrintStream out) {
// Does something clever with `in` and `out`
}
后者是我们可以测试的API - 我们配置协作者,将它们传递给被测系统,然后验证更改。
此时我们还没有对void copy()
进行测试,但是没关系,因为代码很简单,很简单,显然没有任何缺陷&# 34。
请注意,从测试的角度来看,以下设计之间没有太大区别
{
Task task = new Task();
task.copy(in, out);
}
{
Task task = new Task(in, out);
task.copy();
}
{
Task task = Task.createTask();
task.copy(in, out)
}
{
Task task = Task.createTask(in, out);
task.copy();
}
一种思考方式是:我们不首先编写API,首先编写 test 。
// Arrange the test context to be in the correct initial state
// ???
// Verify that the test context arrived in final state consistent with the specification.
也就是说,在开始考虑API之前,首先需要弄清楚如何评估结果。
同样的想法,不同的拼写:如果函数调用的效果是不可检测的,那么你也可以只发出一个no-op。如果一个no-op不能满足你的要求,那么某处必须有一个可观察到的效果 - 你只需要弄清楚是直接观察到这种效应(检查一个返回值),还是通过代理(检查效果)解决方案中的其他一些元素,或者扮演该元素角色的测试双方。)
好的,现在我可以将params传递给测试它的方法,但是我可以测试什么?
你测试它应该做什么。
尝试这个思想实验 - 假设你和我配对,你提出了这个界面
interface Task {
void lookForChanges();
}
然后,经过一番仔细考虑,我实现了这个:
class NoOpTask implements Task {
@Override
void lookForChanges() {}
}
您如何证明我的实施不满足要求?
你在问题中写的是"它更新数据库并向客户端发送JMS消息"所以有两个断言要考虑 - 数据库是否得到更新,并且是JMS消息发出?
整件事看起来像这样
Given:
A database with data `A`
A webservice with data `B`
A JMS client with no messages
When:
The task is connected to this database, webservice, and JMS client
and the task is run
Then:
The database is updated with data `B`
The JMS client has a message.
看起来你建议的是端到端测试。
它看起来像一个。但是如果你对这些协作者而不是实时系统使用测试双打,那么你的测试就是在一个孤立且确定的shell中运行。
它可能是一个社交测试 - 测试在when子句中不知道或不关心被测系统的实现细节。我没有声称SUT是单一的#34;单位"。
我必须首先看到foo的实现。我错了吗?
是的 - 您需要了解foo的规范,而不是实现。