使用原始数组/指针参数验证Objective-C中的方法调用

时间:2013-01-21 18:07:55

标签: objective-c unit-testing mocking ocmock ocmockito

我正在测试的类中有两种方法:

- (NSUInteger)sendBuffer:(uint8_t *)buffer length:(NSUInteger)length;
- (BOOL)sendFormattedCommandForAddress:(uint8_t)address 
                              withData:(uint8_t)data 
                        andCommandType:(ZKZSensorCommandType)commandType;

-sendFormattedCommandForAddress:withData:andCommandType:构建一个char数组,并将指向此数组的指针传递给-sendBuffer:length:。此数组的内容取决于addressdatacommandType。在我的测试中,我想验证是否构建了正确的数组并将其传递给-sendBuffer:length:。 OCMock不会让我对uint8_t *参数设定期望。 OCMockito / OCHamcrest不会让我使用部分模拟(还)。我试过调用-sendBuffer:length:方法,调用我的测试用例类中的方法,并设置对该方法调用的期望。但是,当调用swizzled方法时,self指向被测试的类而不是我的测试用例。我可以在我的测试类中保留缓冲区,然后在我的测试中检查这个缓冲区的内容,但我讨厌在生产代码中添加一些东西只是为了支持测试。有没有人对如何测试这种行为有更好的建议?

2 个答案:

答案 0 :(得分:0)

虽然这可以说是一个观点问题,但全面的单元测试的好处使代码复杂性的一个小的和包含的增加值得权衡。在您描述的情况下,我认为您想要在生产类中添加一个缓冲区,以便在单元测试中检索并声明发送的最后一个字节序列是一种非常好的方法。

我个人可能会添加一个布尔属性来控制缓冲区是否被维护,只是为了避免在生产代码中发送大量消息时出现意外的不必要的内存开销。单元测试设置当然会设置此属性,而应用程序/框架生产代码则不会。同样,关键是使添加的代码变得如此简单以至于显然是正确的。 : - )

如果您希望或需要严格遵守生产类所公开的接口,您还可以考虑使缓冲区维护代码依赖于条件编译。我个人更喜欢前一种方法,但对每一种方法都是如此。

答案 1 :(得分:0)

你不需要一个模拟框架来制作模拟。我认为,挑战在于你实际上并不想要致电-sendBuffer:length:。在这种情况下,只需使用子类和覆盖方法,如Michael Feathers的书有效地使用遗留代码中所述。

不知道你班级的名字,我称之为Sender。这就是我要写的内容,直接写入SenderTest.m:

@interface TestingSender : Sender
@property (assign, nonatomic) NSUInteger sendBufferCount;
@property (assign, nonatomic) uint8_t *sendBufferBuffer;
@property (assign, nonatomic) NSUInteger sendBufferLength;
@end

@implementation TestingSender

- (NSUInteger)sendBuffer:(uint8_t *)buffer length:(NSUInteger)length
{
    ++_sendBufferCount;
    _sendBufferBuffer = buffer;
    _sendBufferLength = length;
}

@end

然后,测试代码会创建一个TestingSender而不是Sender。

相关问题