2016-07-14 26 views
1

我开始了一些原型代码,沿着这些路线云:设计类调用外部API时测试实现是否正确?

// Omitted most definitions, return values checks, etc. 
// The real code is much bigger and uglier. 
serverId = socket(AD_INET, SOCK_STREAM, PROTO_ANY); 
setsockopt(serverId, SOL_SOCKET, SO_REUSEADDR, &reuseAddrOk, sizeof(int)); 
bind(serverId, &serverAddress, sizeof(serverAddress)); 
listen(serverId, waitQueueSize); 
clientId = accept(serverId, &clientAddress, sizeof(clientAddress)); 
read(clientId, clientBuffer, charsToRead); 

现在我想很简单的类来重构这个代码提取功能(不是要刁难现在很一般... YAGNI)。这是我想的接口类型:

SocketServer server = SocketServer(parameters); 
// SocketServer knows how to create a SocketClient...abstract factories, dependency injection, etc. etc. 
SocketClient client = server.accept(); 
string clientMessage = client.read(); 
client.write(serverMessage); 

例如,SocketServer类封装了所有样板创建一个新的socket服务器:

SocketServer server = SocketServer(parameters); 

然后,因为这需要调用系统API,我需要嘲笑它:

SocketServer server = SocketServer(systemAPI, parameters); 

现在,测试这段代码是否正确是什么意思?它不会产生任何我可以检查的输出(或者更好,我完全是这样做来封装输出,就像文件描述符一样)。我可以检查模拟API的正确方法被调用,如:

testSocketCalledWithCorrectParameters() { 
    systemAPI = mock(SystemAPI).expect(once()).method("socket").with(
     SystemAPI.AF_INET, 
     SystemAPI.SOCK_STREAM, 
     SystemAPI.PROTO_AUTO 
    ); 
    ServerSocket(systemAPI, parameters); 
} 

这是一个正确的情况,我应该依靠测试的实现,而不是接口的?是不是被迫测试一个实现而不是一个糟糕设计的接口?

所有其他测试中,我能想到的关于执行设定的期望:

testServerSocketIsCreatedWithCorrectDescriptor() { 
    dummyDescriptor = 10; 
    systemAPI = mock(SystemAPI).when("socket").return(dummyDescriptor); 
    server = SocketServer(systemAPI, parameters); 
    assertEquals(dummyDescriptor, server.descriptor); 
} 

/** 
* @expected SocketException 
*/ 
testThrowsExceptionIfErrorCreatingSocket() { 
    systemAPI = mock(SystemAPI).when("socket").return(SystemAPI.RETURN_ERROR); 
    SocketServer(systemAPI, parameters); 
} 

// etc. 

然后,我应该写单元测试也为socketAPI,或者想当然地认为这将是一个非常要我只拿愚蠢的包装类,除了将调用委托给外部API(因此不需要测试)之外,什么也不做?

+0

如果当提供'Z'时'X'应该做'Y',你会如何测试它?您将调用'X',提供'Y'并测试'Z'的结果。如果你不能,你需要编写可以让你这样做的基础设施。 –

+0

“*测试实现而不是接口*” - 测试接口意味着什么? –

+0

@OliverCharlesworth如果我有一个函数'add(a,b)',我可以测试'add(1,2)== 3'和'add(10,1)== 11',无论这个函数如何实现。 – swahnee

回答

0

让我试着一一回答。

1.测试通话性能

这种测试的只有documentational值(这是调用API的方式。)检查,如果真的是值得的 - >也许陈述不够清楚在你的代码中。

2. testServerSocketIsCreatedWithCorrectDescriptor

对我来说,这种测试有更多的价值。我几乎总是写一个testCreation,它显示:输入参数和断言属性,例如一辆汽车需要施工车轮,然后默认有4个车轮,红色和一个方向盘。

3 testThrowsExceptionIfErrorCreatingSocket

这种测试是最有价值的。他们定义并保护您的班级在不同情况下的行为。我在这里错过了一个断言,例如抛出的那种异常。 尽可能多地写这种测试。

4。测试系统API

否。不要在单元测试中测试系统行为。特别是不嘲笑。 这是模块或端到端测试的一部分。

希望这会有所帮助。

+0

谢谢你的回答。 “测试通话属性”是什么意思?测试模拟的某些方法被称为一定的时间?在情况2中,您是否认为仅为测试目的而暴露通常会隐藏的属性(作为实现的一部分)是值得的?同意更专注于测试特殊情况。 – swahnee

+0

是的,我的意思是测试模拟中的某些方法被调用,并传递哪些参数。在案例2中:你的意思是仅仅为了测试目的而暴露server.descriptor - 不是一个好主意。我的提示:听你的测试,他们经常发现严重的设计缺陷。如果测试困难且令人毛骨悚然 - 这是您的设计,而不是测试的错误 – mrAtari

相关问题