如何在目标 c 中模拟类方法以与 TDD 一起使用

Posted

技术标签:

【中文标题】如何在目标 c 中模拟类方法以与 TDD 一起使用【英文标题】:How to mock class methods in objective c to use with TDD 【发布时间】:2012-09-12 20:43:37 【问题描述】:

我正在使用第三方框架将数据发送到服务器。我正在嘲笑该第三方框架以隔离和测试我的代码如何与之交互。这是为了避免在单元测试时避免等待从网络取回数据,并且因为我想测试我编写的错误处理代码。

我没有使用 OCMock 或类似的东西,我正在通过继承 3rd 方框架来编写自己的模拟对象。

我的方法是这样的-

- (void)loginWithCredentials:(NSDictionary *)credentials

    NSDictionary *credentials = [self credentials];
    NSString *username = [credentials objectForKey:kUserCredintialUsername];
    NSString *password = [credentials objectForKey:kUserCredintialPassword];

    [ThirdPartyClass loginWithUsername:username 
                           andPassword:password 
                                 block:^(ThirdPartyClass *user, NSError *error)
    if (user) 
        NSLog(@"We logged in");
    
    else if (error) 
        NSLog(@"%@", [error errorString]);
    
];

我想做的是在我的单元测试中调用loginWithUsername:andPassword:block:。当前的方法显然是不可测试的,因为它没有遵循“告诉,不要问”(我没有告诉loginWithCredentials: 哪个类调用loginWithUser...block:)。我能想到解决这个问题的唯一方法是向我的实例或类添加一个类变量,或者向loginWithCredentials: 添加一个参数,这样我就可以替换我的模拟了。生产代码这样做并没有得到任何清晰 -它已经被编写为 3rd 方库的适配器。相反,我更愿意尝试重构 loginWithCredentials: 方法。

【问题讨论】:

您可以调配类方法以将 loginWithUsername:andPassword:block: 替换为存根或伪造(即 ***.com/questions/3267506/…)。您是否有任何理由不想使用可以提供这种行为的测试库?我是github.com/allending/Kiwi 的粉丝,它可以让您编写像[[[ThirdPartClass] should] receive:@selector(loginWithUsername:andPassword:block:) andReturn:mockObject] 这样的语句。我发现这比手动调配方法要容易得多,尤其是因为我不必撤消调配。 我曾考虑过 swizzling,但它看起来相当脆弱,我担心如果做得不对,我可能会收到错误的单元测试通过确认。这个问题还散发出一种代码味道,我可能会以不太理想的方式编写我的方法。至于测试库,我只是想避免在我的代码中容纳另一个第三方库。 【参考方案1】:

https://github.com/AliSoftware/OHHTTPStubs 有一个 HTTP 存根库。它通过捕获传出请求并返回文件数据来工作。它还允许对不同类型网络的加载速度进行初步模拟。

【讨论】:

以上是关于如何在目标 c 中模拟类方法以与 TDD 一起使用的主要内容,如果未能解决你的问题,请参考以下文章

将自定义对象转换为 NSData 以与 NSFileManager 一起使用

如何在 Windows 上安装 pyodbc 以与 Python 3.8 一起使用?

如何设置安装了 conda 的 R 以与 RStudio 一起使用?

如何将公式转换为变量以与 R 中的 fastLm 函数一起使用

TDD学习笔记一Unit Test - Stub, Mock, Fake 简介

如何将基于自定义图像的数据集加载到 Pytorch 中以与 CNN 一起使用?