天天改需求,你还有完没完!之感知与分离
共 2957字,需浏览 6分钟
·
2021-09-06 20:23
感知与分离到底是什么?
理想情况下我们无须对一个类做什么处理就可以进行测试了,在理想的系统中我们应该能够在测试工具中创建任何类的对象并对其进行测试,理想状态下就意味着根本无法在现实中完成,实际情况往往是非常复杂的,类之间的依赖会导致我们难以将一簇对象放入测试中,要创建某个类的对象的时候或许又要先创建另一个类的对象,而后者的创建又要用到其他类的对象,这样几乎大家都会有牵扯,最后把整个系统全部牵进来测试,或许有时候也不算问题 ,若是对于c++这样的语言来说,如果不先解除依赖,则光是连接所耗费的时间 就会让“快速周转”告吹;
对于开发时没有编写同步测试的系统,我们要先解除依赖才能测试某个类,这其实不是解除依赖的唯一原因,有时候我们要测试的类会对其他的类产生影响,这是我们测试必须要提前知道的,怎么知道呢?可以利用别影响的类的接口来感知,也就是伪装成被影响的类来感知他所受到的影响,注意,如果没有接触依赖这个方法可行不通!
通常,我们想要测试成功的话,有两个原因进行解除依赖,这俩原因就是今天的重头戏:
1.感知:当我们无法访问到代码计算出的值的时候,就需要通过解除依赖来感知;
2.分离:当我们无法把一段代码做测试的时候,就需要解除依赖把这段代码分离出来;
public class NetworkBridge{
public NetworkBridge(EndPoint [] endPoints){
……
}
public void formRouting(String sourceID,String destID){
……
}
……
}
NetworkBridge的构造函数接收到EndPoint数组,并通过一些本地硬件来管理他们的配置,NetworkBridge的用户能够通过改变相应的EndPoint的设置,EndPoint每个实例都打开一个套接字,然后通过网络通过一个特定的设备进行通信,也就是通过其功能跟踪数据流从一个端点到另一个端点;
不是友军,就伪装成友军
在处理遗留代码的过程中一个重要而又棘手的问题就是依赖,如果想通过仅仅执行一段代码来看他到底是什么功能的话,通常必须先要解开该代码与其他代码之间的依赖才行,但是解开依赖远没有你想的那么简单,往往这里的其他代码正是容易感知到我们的行为所产生的影响的地方,如果可以用另一些代码来取代其位置并通过这些代码进行测试的话,我刚才说的另一些代码就是伪对象;
所谓的伪对象就是那些在测试中用于伪装成被测试类的“合作者”的对象,来看下面这个例子:比如有这样一个类:
如果我们想测试一下Sale类是否能正常工作,可以再添加一个类,两者进行通信:
Sale不但可以持有ADisplay,还可以持有其他类的对象,比如FakeDisplay,在这里FakeDisplay就是个伪装成友军的人,我们可以基于这个伪装者进行测试;
首先,Sale接收一个display为参数,这个display可以是任何实现了Display接口的类的对象;
public interface Display{
void showLine(String line);
}
让伪装者也实现Display接口,Sale对象可以通过构造函数的参数来获取display的引用,并把其存放在自己的内部成员中;
public class Sale{
public Sale(Display display){
this.display=display;
}
public void scan(String barcode){
……
String itemLine=item.name()+" "+item.price().asDisplayText();
display.showLine(itemLine);
……
}
}
scan函数的调用背后发生了什么取决于Sale对象,下面再写一个测试:
import junit.framework.*;
public class SaleTest extends TestCase
{
public void testDisplayAnTtem()
{
FakeDisplay display=new FakeDisplay();
Sale sale=new Sale(display);
sale.scan("131");
assertEquals("asdad",display.getLastLine());
}
}
public class FakeDisplay implements Display
{
private String lastLine="";
public void showLine(String line)
{
lastLine=line;
}
public String getLastLine()
{
return lastLine;
}
}
伪装成友军的人通常都有两张脸,FakeDisplay也不例外,一方面FakeDisplay必须有showLine函数,因为它实现了Display接口,同时showLine还是Display接口上的唯一的函数,也是Sale唯一一个可以“感知”到的函数,另一方面,getLastLine又是为测试而写的;
更高一层:伪装不成,还能模仿!
伪对象不仅实现起来相对容易,而且还是个非常好用的感知工具,如果你要写很多伪对象的话,或许就要考虑一下仿对象了,仿对象是在内部进行断言检查的伪对象;
import junit.framework.*;
public class SaleTest extends TestCase
{
public void testDisplayAnItem()
{
MockDisplay display=new MockDisplay();
display.setException("showLine","scadsa");
Sale sale=new Sale(display);
sale.scan("1");
display.verity();
}
}
总结
这就是感知与分离,下一篇讲解接缝模型。