我有一个系统,它以某种ABC格式从外部系统获取对象列表,将其转换为内部表示并传递给外部服务:
class ABCService() {
public ABCService(ExtService extService) {
this.extService = extService;
}
public void do(ABCData [] abcObjs) throws NoDataException {
if (abcObjs.length == 0) {
throw NoDataException();
} else {
List<Data> objs = new ArrayList<>();
for (ABCData abcObj : abcObjs) {
Data obj = Parser.parse(abcObj); // static call
objs.add(obj);
}
extService.do(objs);
}
}
}
在测试ABCService时,我们可以测试两件事:
但是,虽然Parser工厂也经过测试,但无法保证输出“objs”数组以某种方式连接到输入abcObjs(例如,方法已创建具有预定义长度的列表,但方法“忘记”填充列表)
我认为这两个测试用例并没有完全覆盖方法的工作流程,导致其中一些测试用例未经测试。
如何修改ABCService设计以提高其可测试性?
答案 0 :(得分:1)
此代码中的主要测试难点是您有两个协作者,其中一个是静态的。
如果您可以将Parser
转换为非静态(或者可能将其包装在非静态中)并在执行extService
时注入,则可以测试是否调用了解析器使用正确的参数进行正确的次数。在解析器的返回值中进行存根,您还可以验证是否使用适当转换的对象调用了extService
,而不是仅使用正确数量的对象。
答案 1 :(得分:0)
您遇到的问题是尝试在一个函数中处理两个任务。函数 do 可以在逻辑上分成两个不同的成员函数,这样你就可以对每个函数使用unittest。
通过使用重构,您可以将解析和填充逻辑提取到另一个成员函数中。
class ABCService() {
public void do(ABCData [] abcObjs) throws NoDataException {
extService.do(populateList(abcObjs));
}
List<Data> popuateList(ABCData[] abcObjs) {
if (abcObjs.length == 0) {
throw NoDataException();
} else {
List<Data> objs = new ArrayList<>();
for (ABCData abcObj : abcObjs) {
Data obj = Parser.parse(abcObj); // static call
objs.add(obj);
return objs;
}
}
}
虽然您当前的unittest仍然可以保留“do”功能,另外,您可以为“populateList”函数添加unittest案例以确保它生成正确的数据列表