目标C-单元测试私有方法中的核心功能



我遇到过很多情况,其中我的核心逻辑是在私有方法中。你将如何进行单元测试,有没有任何编译时操作来忽略未知/私有方法的编译错误?我知道对于代码的第二部分,我可以使用performSelector,但这是一个合理的解决方案吗?

例如:

[[self.objectMock expect] privateMethod];
or 
[self.object callPrivateMethodsToExpectSomeOtherBehaviour]

编辑:

这里有一个例子来说明为什么我觉得我需要测试一些私有方法。这些测试不合理吗?否则,我该如何测试调用clear是否真的做到了它应该做的事情?

- (void)clear
{
   self.orderNumber = nil;
   [self.items removeAllObjects];
   // Clear the rest of fields
}
- (void)testClearShouldRemoveOrderNumber
{
   Order *order = [[Order alloc] init];
   OCMockObject *orderPartialMock = [OCmockObject partialMockForObject:order];
   [[orderPartialMock.items expect] setOrderNumber:nil];
   [orderPartialMock clear];
   [orderPartialMock verify];
}
- (void)testClearShouldRemoveItems
{
    Order *order = [[Order alloc] init];
    order.items = [[OCMockObject niceMockForClass:[NSMutableArray class]];
    [[orderPartialMock.items expect] removeAllObjects];
    [orderPartialMock performSelector@selector(clear)];
    [orderPartialMock.items verify];
}

方法从来都不是"私有"的,因为一旦类实现了一个方法,它就可以发送给任何人。

所以,假设您有一个类Foo,它有一个不在接口声明中的"私有"方法bar。您仍然可以从任何地方调用bar,尽管您可能会得到编译器诊断。

可能最简单的方法是在测试使用的类别中声明方法。例如:

@interface Foo (MyPrivateMethodsUsedForTesting)
- (void)bar;
@end

现在,您可以使用它们,编译器也不会抱怨。注意,这些方法不必在实际的MyPrivateMethodsUsedForTesting类别中实现。这种技术有时也被称为"非正式协议"

编辑

此外,正如其他人所指出的,如果你需要访问私有方法,你可能应该重新审视你的设计。在做了大约30年之后,肯定会有一些时候,尤其是在测试中,你需要访问私人内容,但大多数时候这意味着某种类型的设计审查是有序的。

您不应该直接测试您的私有方法。相反,您需要通过公共方法对它们进行测试。这是programmers.stackexchange.com上讨论此事的一个问题的链接。

答案的总体思想是,您(或维护代码的任何其他人)应该可以随时通过更改签名、更改实现或完全删除它们来自由更改您的私有方法。班外的任何人都不应该在意——毕竟,这是最初将这些方法私有化的主要驱动因素。

如果您以不兼容的方式更改您的私有方法,那么您的公共方法的单元测试必须中断;否则,您没有很好地测试您的公共方法。实际上,这使得私有方法的单元测试变得不必要。

通常,您不需要对私有方法进行单元测试。

公开的方法告诉你你的类做什么——这是你关心的,你应该测试这些。私有方法关心你的类是如何完成它的工作的,你的测试不应该关心工作是如何完成的,只要它做得正确。

如果有一天你决定改变你的类的工作方式(即通过改变你的私有方法中的代码),而不改变你的类实际做了什么,那么你的单元测试应该会继续通过。通过尝试测试你的类内部,你创建了一个脆弱的测试,即使类仍然正常工作,它也可能会中断。

如果你发现仅仅使用公共方法很难彻底测试你的类,那么这是一个警告信号,表明你的类可能太大了——考虑把它分解成更小的部分。

您不需要对这些进行单元测试,事实上您不应该这样做
您将通过公共方法间接测试您的privat方法。私有方法是为公共方法完成任务的辅助方法。

既然你应该有足够的自由来更改你的私有方法,那么单元测试也会适得其反。

但是一定要测试公共方法的所有情况,这样所有私有方法都会被覆盖。

最新更新