繁体   English   中英

用 Swift 模拟

[英]Mocking with Swift

考虑以下用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 不适用于 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实例来测试SomeClass 的foo() 这是我不喜欢也不推荐的东西

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

笔记:

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

因此,您想测试一个方法 ( foo ) 是否调用了另一个方法 ( bar )。 foo方法是被测试的方法,而bar方法在更广泛的意义上是一个依赖组件。

如果bar的调用具有持久的副作用,您可以通过测试是否存在/不存在副作用来逃避,也许是通过查询属性或类似的。 在这种情况下,您不需要模拟或类似的东西。

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

您可以将这两种方法放入单独的类中,在这种情况下,类边界就是接缝。 使用协议或只是非正式约定,您就可以完全替换实现bar的类。 依赖注入在这里派上用场。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM