简体   繁体   English

您如何在Swift中编写模拟?

[英]How do you write a mock in Swift?

Where do I put the mocked code? 我将模拟代码放在哪里? Do I need to write everything again? 我是否需要再次编写所有内容? Do I change the original code? 我要更改原始代码吗?

Short answer: using protocols. 简短的答案:使用协议。

If your injectable object is final, a struct, or an enum, it isn't even possible to override it to mock. 如果您的可注入对象是最终对象,结构或枚举,则甚至无法覆盖它以进行模拟。 Instead of using a concrete type as your dependency, use a protocol and conform your implementation to it. 不要使用具体类型作为依赖项,而应使用协议并使您的实现符合该协议。 In addition to allowing "mocking" regardless of the real type (class, struct, enum), this lists the public interface all in one place, uninterrupted by the implementations. 除了允许不管真实类型(类,结构,枚举)如何进行“模拟”之外,它还在一个地方列出了公共接口,不受实现的干扰。 It also forces you to think about what needs to be part of the non-private interface. 这也迫使您考虑需要成为非私有接口的一部分。

With retroactive protocol conformance (ie in extensions), you can even use this to mock system classes like, eg, CBCentralManager or CLLocationManager . 使用追溯协议一致性(即扩展名),您甚至可以使用它来模拟系统类,例如CBCentralManagerCLLocationManager

Example: 例:

Not easily mockable: 不容易嘲笑:

struct Foo {
    let id: Int
    let data: Int
}

final class FooManager {
    var x: Int

    func getFoo(id: Int) -> Foo {
        return Foo(id: id, data: x)
    }
}

class FooUser {
    let fooManager: FooManager
    init(fooManager: FooManager) {
        self.fooManager = fooManager
    }
    func getData() -> Int {
        return fooManager.getFoo(id: 3).data
    }
}

Trivially mockable: 可嘲弄的:

struct Foo {
    let id: Int
    let data: Int
}

// Easy to see what's visible.
protocol FooManager {
    func getFoo(id: Int) -> Foo
}

final class RealFooManager: FooManager {
    private var x: Int

    func getFoo(id: Int) -> Foo {
        return Foo(id: id, data: x)
    }
}

class FooUser {
    let fooManager: FooManager
    init(fooManager: FooManager) {
        self.fooManager = fooManager
    }
    func getData() -> Int {
        return fooManager.getFoo(id: 3).data
    }
}

// In test target.
class MockFooManager: FooManager {
    var requestedId: Int?
    var data: Int = 17
    func getFoo(id: Int) -> Foo {
        requestedId = id
        return Foo(id, data: data)
    }
}

class FooUserTests {
    func testFooUserGetData() {
        let mock = MockFooManager()
        let user = FooUser(fooManager: mock)
        let data = user.getData()
        XCTAssertEqual(data, mock.data)
        XCTAssertEqual(mock.requestedId, 3)
    }
}

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

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