我有一个方法:

-(void)startTaskForResult:(long long*)result {
  ...
}

我要进行单元测试的函数调用上述函数:
-(void)doWork {
 long long result = 0;
 [self startTaskForResult:&result];
}

我正在使用OCMock库进行单元测试。在我的测试案例中,我想将result参数设置为模拟值,例如100无需关心-(void)startTaskForResult:(long long*)result的实际实现。

我尝试了以下方法:
-(void)testDoWork{
// try to set 100 to argument 'result'
OCMStub([classToTest startTaskForResult:[OCMArg setToValue:OCMOCK_VALUE((long long){100})]]);
// run the function, but it doesn't use mocked value 100 for argument 'result'
[classToTest doWork];
...
}

但是,当我运行测试时,它不会将模拟值100用于参数result。那么在我的情况下将模拟值设置为参数的正确方法是什么?

最佳答案

几点可以回答您的问题:

您的问题的代码:

- (void)testDoWork
{
    id mock = OCMPartialMock(classToTest)
    OCMStub([mock startTaskForResult:[OCMArg setToValue:OCMOCK_VALUE((long long){100})]]).andForwardToRealObject;
    // set your expectation here
    [classToTest doWork];
}
  • 要解决您的特定问题:
  • 您的对象应该是部分模拟
  • 您的方法应该存根(您做到了)
  • 您的存根应该转发给真实对象(我假设您需要调用startTaskForResult:实现方法)
  • 但是,由于使用了错误的测试方法,因此您会遇到问题。

  • 编写单元测试有3种最常见的策略:
  • 用于测试方法的Arrange-Act-Assert
  • 给定-何时-然后用于测试函数
  • Setup-Record-Verify用于测试副作用。这通常需要嘲笑。

  • 所以:
  • 如果要测试startTaskForResult:是否返回特定值,则应仅调用该方法并期望返回值(不是您的情况,方法返回类型为void)
  • 如果方法更改了对象的状态-您应该期望状态更改,例如属性值等等
  • 如果调用doWork具有调用startTaskForResult:的副作用,则应将其存根并期望它被调用,就像我在上面的代码中编写的一样。但是(!!!),但是您不应该期望这样的事情。这不是一种需要测试的行为,因为它是内部类实现的详细信息。一种可能的情况是,当两个方法都是 public 的并且在类协定中明确声明时,一个方法应通过一些初步设置调用另一个方法。在这种情况下,您期望方法调用带有一些状态/参数。

  • 为了使您的应用程序代码可测试,您需要不断重构代码。有些代码是不可测试的,最好采用应用程序代码,而不要尝试用测试覆盖它。您失去了测试的最初目标-重构安全性和进行更改的低成本。

    关于ios - 在单元测试中,将模拟值设置为参数(按引用传递),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/39152107/

    10-09 19:20
    查看更多