MockItYourself 1.1.3

MockItYourself 1.1.3

测试已测试
Lang语言 SwiftSwift
许可证 MIT
发布上次发布2016年8月
SPM支持SPM

维护者:Jóhann Þorvaldur Bergþórsson



  • Alexey Verein,Jóhann Þ. Bergþórsson,Magnus Ó. Magnússon和Alexander A. Helgason

MockItYourself

MockItYourself是为Swift创建模拟框架的尝试。在Swift中目前不能动态创建类,因此无法创建类似OCMock这样的强大模拟框架。MockItYourself是减少手动创建模拟所需的冗余代码的尝试。

MockItYourself受到了SwiftMock的很大启发,从某些方面来看,可以被视为该项目的分支。

安装

MockItYourself可以通过CocoaPods获取。要安装,只需将以下行添加到您的Podfile中:

source 'https://github.com/CocoaPods/Specs.git'

use_frameworks!

target 'MyApp' do

end

target 'MyApp_Tests', :exclusive => true do
    pod 'MockItYourself', '1.0.0'
end

动机

在Swift中模拟依赖项的标准方式是手动创建自己的模拟

class Dependency {
    func slowAndExpensiveMethod(arg1: String, arg2: Int) -> Double {
        print("Do something really slow and expensive with arguments")
        return 40.0
    }
}

class MockDependency: Dependency {
    var didCallSlowAndExpensiveMethod: Bool = false
    var lastCalledArg1: String?
    var lastCalledArg2: Int?

    override func slowAndExpensiveMethod(arg1: String, arg2: Int) -> Double {
        didCallSlowAndExpensiveMethod = true
        lastCalledArg1 = arg1
        lastCalledArg2 = arg2

        return 50.0
    }
}

struct ObjectUnderTests {
    let dependency: Dependency

    func method() -> Double {
        let result = dependency.slowAndExpensiveMethod("A", arg2: 1)
        return result / 2
    }
}

class MockExampleTests: XCTestCase {
    var mockDependency: MockDependency!
    var objectUnderTest: ObjectUnderTests!

    override func setUp() {
        mockDependency = MockDependency()
        objectUnderTest = ObjectUnderTests(dependency: mockDependency)
    }

    func test_did_call_method_on_dependency_with_correct_arguments() {
        let _ = objectUnderTest.method()

        XCTAssert(mockDependency.didCallSlowAndExpensiveMethod)
        XCTAssertEqual(mockDependency.lastCalledArg1, "A")
        XCTAssertEqual(mockDependency.lastCalledArg2, 1)
    }

    func test_method_returns_correct_result_given_dependency_returns_50() {
        let result = objectUnderTest.method()

        XCTAssertEqual(result, 25.0)
    }
}

这很快变得繁琐,而MockItYourself是减少冗余代码的尝试。

class Dependency {
    func slowAndExpensiveMethod(arg1: String, arg2: Int) -> Double {
        print("Do something really slow and expensive with arguments")
        return 40.0
    }
}

class MockDependency: Dependency, MockItYourself {
    let callHandler = MockCallHandler()

    override func slowAndExpensiveMethod(arg1: String, arg2: Int) -> Double {
        return callHandler.registerCall(args: Args2(arg(arg1), arg(arg2)), defaultReturnValue: 50) as! Double
    }
}

struct ObjectUnderTests {
    let dependency: Dependency

    func method() -> Double {
        let result = dependency.slowAndExpensiveMethod("A", arg2: 1)
        return result / 2
    }
}

class MockExampleTests: XCTestCase {
    var mockDependency: MockDependency!
    var objectUnderTest: ObjectUnderTests!

    override func setUp() {
        mockDependency = MockDependency()
        objectUnderTest = ObjectUnderTests(dependency: mockDependency)
    }

    func test_did_call_method_on_dependency_with_correct_arguments() {
        let _ = objectUnderTest.method()

        verify(mockDependency) { self.mockDependency.slowAndExpensiveMethod("A", arg2: 1) }
    }

    func test_method_returns_correct_result_given_dependency_returns_50() {
        stub(mockDependency, andReturnValue: 50) { mockDependency.slowAndExpensiveMethod("A", arg2: 1) }

        let result = objectUnderTest.method()

        XCTAssertEqual(result, 25.0)
    }
}

用法

MockItYourself帮助减少手动创建模拟时的冗余代码。让我们假设我们有以下类:

class Dependency {
    func slowAndExpensiveMethod(arg1: String, arg2: Int) -> Double {
        return 40.0
    }
}

创建模拟很简单

  1. 创建Dependency的子类。
  2. 通过添加一个callHandler属性来实现MockItYourself协议。
  3. 注册您想模拟或存根的方法。
import MockItYourself

class MockDependency: Dependency, MockItYourself {
    let callHandler = MockCallHandler()

    override func slowAndExpensiveMethod(arg1: String, arg2: Int) -> Double {
        return callHandler.registerCall(args: Args2(arg(arg1), arg(arg2)), defaultReturnValue: 50)
    }
}

验证

MockItYourself允许您通过检查您的模拟上的方法是否调用来验证:

验证方法被调用

func test_verify() {
    mock.slowAndExpensiveMethod("A", arg2: 1)

    verify(mock) { self.mock.slowAndExpensiveMethod(any(), arg2: any()) }
}

验证方法被调用n次

func test_verify_number_of_calls() {
    mock.slowAndExpensiveMethod("A", arg2: 1)
    mock.slowAndExpensiveMethod("A", arg2: 1)

    verify(mock, expectedCallCount: 2) { self.mock.slowAndExpensiveMethod(any(), arg2: any()) }
}

验证方法被调用,并且传递了特定的参数

func test_verify_with_arguments() {
    mock.slowAndExpensiveMethod("A", arg2: 1)

    verify(mock, checkArguments: true) { self.mock.slowAndExpensiveMethod("A", arg2: 1) }
}

拒绝

验证方法没有被调用

func test_reject() {
    reject(mock) { self.mock.slowAndExpensiveMethod("A", arg2: 1) }
}

存根

存根方法或属性的返回值

func test_stubbing() {
    stub(mock, andReturnValue: 30) { self.mock.slowAndExpensiveMethod("A", arg2: 1) }

    let returnValue = mock.slowAndExpensiveMethod("A", arg2: 1)
    XCTAssertEqual(returnValue, 30)
}

作者

许可证

MockItYourself 在MIT许可证下提供。更多信息请参阅LICENSE文件。