Objective C - 如何在私有方法中进行核心功能的单元测试?

9

我曾经遇到过很多核心逻辑都在私有方法中的情况。你如何进行单元测试呢?是否有一种编译时操作可以忽略未知/私有方法的编译错误?我知道对于代码的第二部分,我可以使用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];
}
4个回答

13

在某种意义上,方法永远不会是“私有的”,因为一旦一个类实现了一个方法,任何人都可以发送它。

所以,假设您有一个类 Foo,其中有一个未在接口声明中的“私有”方法 bar。无论从哪里,您仍然可以调用 bar,尽管可能会得到编译器诊断。

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

@interface Foo (MyPrivateMethodsUsedForTesting)
- (void)bar;
@end
现在,你可以使用它们而不会引起编译器的投诉。请注意,方法不必在实际的MyPrivateMethodsUsedForTesting类别中进行实现。这种技术有时也被称为“非正式协议”。
编辑:
另外,正如其他人所指出的那样,如果需要访问私有方法,则可能应该重新审查设计。在做了大约30年的这个行业之后,肯定有时候需要访问私有内容,尤其是测试方面,但大多数情况下意味着需要进行某种类型的设计审查。

1
“private”类怎么办?也就是说,那些@interface.m文件中的类? - Ky -

9
你不应该直接测试你的私有方法,而是需要通过公共方法来测试它们。这里有一个链接指向programmers.stackexchange.com上的一个问题讨论此事。
答案的一般思路是,你(或者维护你代码的任何其他人)应该随时自由地通过更改签名、改变实现或完全删除私有方法来更改它们。在类外部没有人应该关心 - 毕竟,这是将这些方法设为私有的主要原因。
如果你以不兼容的方式更改了你的私有方法,那么你的公共方法的单元测试必须失败;否则,你没有很好地测试你的公共方法。有效地,这使得私有方法的单元测试变得无关紧要。

1
我想为最后一段点赞不止一次。 - Gordonium

5
通常情况下,您不需要对私有方法进行单元测试。公开的方法告诉您类的功能 - 这是您关心的内容,因此应该测试这些方法。私有方法涉及类如何执行其工作,测试不应关心工作如何完成,只要正确完成即可。
如果有一天您决定更改类执行其工作的方式(即通过更改私有方法中的代码),而不更改类实际执行的内容,则您的单元测试应继续通过。试图测试类的内部机制会创建脆弱的测试,即使类仍然正常工作,也可能导致测试失败。
如果您发现仅使用公共方法无法充分测试类,则这表明您的类可能过于庞大 - 考虑将其拆分为较小的组件。

0

你不需要对这些进行单元测试 - 实际上你也不应该这样做。
你将通过公共方法间接地测试你的私有方法。私有方法是帮助公共方法完成任务的辅助方法。

由于你应该自由地更改私有方法,因此单元测试也会产生反作用。

但一定要测试所有公共方法的情况,以便覆盖所有私有方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接