ios - 用 Swift 模拟

标签 ios objective-c swift ocmock

考虑以下用 Swift 编写的名为 SomeClass 的类:

@objc class SomeClass: NSObject
{
    var shouldCallBar = false

    func foo()
    {
        if (shouldCallBar == true)
        {
            bar()
        }
    }

    func bar()
    {
    }
}

为了测试上面的类 foo() 方法(以及主要用 Objective-C 编写的类似场景),我使用了 OCMock,如下所示:

- (void) testFooBarShouldBeCalledWhenShouldCallBarIsTrue
{
    SomeClass * someClass = [SomeClass new];

    // Create mocks.
    id mockSomeClass = OCMPartialMock(someClass);

    // Expect.
    [[mockSomeClass expect] bar];

    // Stub.
    someClass.shouldCallBar = YES;

    // Run code under test.
    [someClass foo];

    // Verify.
    [mockSomeClass verify];

    // Stop mocking.
    [mockSomeClass stopMocking];
}

但是上面的测试失败了,Swift 代码为 OCMock won't works well with Swift .

所以我正在考虑完全使用 Swift 的东西:

class SomeClassTests: XCTestCase
{
    class MockSomeClass: SomeClass
    {
        var isBarCalled = false

        override func bar()
        {
            isBarCalled = true
        }
    }

    func testBarShouldBeCalledWhenTrue()
    {
        let someClass = MockSomeClass()
        someClass.shouldCallBar = true

        someClass.foo()

        XCTAssertTrue(someClass.isBarCalled == true)
    }
}

请注意,我正在对被测试的原始类进行子类化并覆盖 bar()。我完全没有触及 foo() 实现。

但缺点是我正在使用 MockSomeClass 实例来测试 SomeClassfoo()。这是我不喜欢的,not recommended .

上面的问题有没有更好的解决办法?

注意事项:

  • 我在这里不是在谈论依赖注入(inject)。依赖注入(inject)是完全不同的方法。
  • 我在 UIViewController 中测试 UI 代码时遇到过这类问题。
  • 我想到了基于协议(protocol)的编程,但未能针对上述问题提出解决方案。

最佳答案

因此,您想要测试一个方法 (foo) 调用或不调用另一个方法 (bar)。 foo 方法是被测对象,而 bar 方法在广义上是一个依赖组件。

如果 bar 的调用有持久的副作用,您可以测试是否存在副作用,可能通过查询属性或类似方法。在那种情况下,您不需要模拟或类似的东西。

如果没有副作用,那么您必须替换依赖项。为此,您需要一个接缝,您可以在该接缝处放置可以告诉测试该方法是否已被调用的代码。为此,我只能看到 Jon 已经在 question you refer to 中讨论过的两个选项。 .

你要么将这两个方法放在不同的类中,在这种情况下,类边界就是接缝。使用一个协议(protocol),或者只是一个非正式的约定,您就可以完全替换实现 bar 的类。依赖注入(inject)在这里派上用场。

如果这两个方法必须留在同一个类中,那么您必须使用子类边界作为接缝,即您可以使用可以覆盖方法并实现 test-specific sublass 的事实。 .当您可以使用模拟框架时,这是最简单的。如果那不是一个选项,您必须自己编写代码,就像您在问题中描述的那样。

关于ios - 用 Swift 模拟,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36802678/

相关文章:

iphone - 使用 segue 将 NSMutableArray 字典数据传递到另一个 View

objective-c - Objective-C 中的协议(protocol)是可继承的吗?

触摸选项卡栏项目后快速更改选项卡栏标题

ios - 突出显示/选定状态问题的 UIButton 背景颜色

c# - mvvmcross iOS 绑定(bind)到列表无法将 `lambda expression' 转换为非委托(delegate)类型 `string'

objective-c - block 捕获对象的过度释放问题;保留计数从 +2 直接跳到 0!

ios - 将数据从 TableView 单元格传递到新 View Controller 错误

ios - Realm 获取结果 Controller

ios - 无法在场景中添加多个pod资源

ios - Realm swift : required public init() error