我有3种使用有关其定义如下的特定类的方法:
class MyClass: NSObject {
func myMethod() {
methodA()
methodB()
methodC()
}
func methodA() {}
func methodB() {}
func methodC() {}
}
我需要测试myMethod
呼吁所有3种方法被实现它们的顺序:methodA
然后methodB
然后methodC
要与XCode的单元测试测试,而不管这些方法的实现,我已经创造了看起来测试用例子类像下面这样:
class ChildClass: MyClass {
var method1CallingDate: Date?
var method2CallingDate: Date?
var method3CallingDate: Date?
override func methodA() {
super.methodA()
method1CallingDate = Date()
}
override func methodB() {
super.methodB()
method2CallingDate = Date()
}
override func methodC() {
super.methodC()
method3CallingDate = Date()
}
}
现在,在测试方法中,我开始通过调用这些3种方法,那么我断言,这三个日期是不是零,然后再像这样对它们进行比较:
XCTAssertLessThan(method1CallingDate, method2CallingDate)
XCTAssertLessThan(method2CallingDate, method3CallingDate)
我跑进问题是,测试有时成功,有时会失败,我想由于Date
目的是(随机地)相同的方法调用的2之间。有没有更好的方法来测试调用多种方法的顺序?
附:这是很容易在Android SDK org.mockito.Mockito.inOrder
完成
首先,做一个模仿对象,记录的顺序。无日期,无弦。只是一个枚举。
class MockMyClass: MyClass {
enum invocation {
case methodA
case methodB
case methodC
}
private var invocations: [invocation] = []
override func methodA() {
invocations.append(.methodA)
}
override func methodB() {
invocations.append(.methodB)
}
override func methodC() {
invocations.append(.methodC)
}
func verify(expectedInvocations: [invocation], file: StaticString = #file, line: UInt = #line) {
if invocations != expectedInvocations {
XCTFail("Expected \(expectedInvocations), but got \(invocations)", file: file, line: line)
}
}
}
然后在测试:
mock.verify(expectedInvocations: [.methodA, .methodB, .methodC])
没有异步等待。简单的调用。清除故障信息。
你可以使用String
跟踪订单的做这样的事情:
class ChildClass: MyClass {
var order = ""
override func methodA() {
super.methodA()
order = String((order + "A").suffix(3))
}
override func methodB() {
super.methodB()
order = String((order + "B").suffix(3))
}
override func methodC() {
super.methodC()
order = String((order + "C").suffix(3))
}
}
然后,只需检查order
是"ABC"
。
或者,如果它是有效的调用B
A
和C
之间多次:
class ChildClass: MyClass {
var order = ""
override func methodA() {
super.methodA()
order = order.replacingOccurrences(of: "A", with: "") + "A"
}
override func methodB() {
super.methodB()
order = order.replacingOccurrences(of: "B", with: "") + "B"
}
override func methodC() {
super.methodC()
order = order.replacingOccurrences(of: "C", with: "") + "C"
}
}
例:
let c = ChildClass()
c.methodA()
c.methodB()
c.methodB()
c.methodC()
print(c.order)
ABC
我已经成为使用XCTestExpectation
对于这种事情的粉丝。下面是一个选项。
class MyTestableClass: MyClass {
var methodAHandler: (() -> Void)?
// ...
override func methodA() {
methodAHandler?()
super.methodA()
}
然后在你的测试用例
let expA = XCTestExpectation(description: "Method A Called")
let expB = ...
let expo = ...
objectUnderTest.methodAHandler = { expA.fulfill() }
/// ...
objectUnderTest.myMethod()
// ensure you use the enforceOrder param, which is optional
wait(for: [expA, expB, expC], timeout: 1.0, enforceOrder: true)
XCTestExpectation
由更多的异步测试,所以等待略有滑稽。但是,它确实做到你需要什么,并会继续工作,即使最终myMethod
的内部成为异步出于某种原因。
虽然我没有用它自己,你可能也想看看Cuckoo。它是斯威夫特嘲弄的框架。
你不在这里,提出正确的问题。但从你不应该知道一个单元测试点/关心的测试方法调用其他方法,或者即使存在其他方法。
单元测试应该验证测试方法的一些可观察到的结果。任何所测试的方法内发生的情况是在单元测试的上下文不相关的。
这是因为单元测试应该确认该单位的行为与预期,即他们应当验证对规范,对不执行。
让我们考虑一个简单的例子,单元测试isPrime(n)
功能。除非你在做性能测试,你只有当函数返回一对夫妇数的适当的结果在意。你不介意的功能检查所有可能的除数,或者如果它使用所有已知素数的数据库,或者代表的主要检查一些第三方库/服务。
这种情况是不是从你太大的不同。需要通过测试单元的外部接口进行验证的三种方法被称为按照一定的顺序的事实。例如,如果三个方法进行API调用,然后嘲笑API客户端,并期望它被请求三次,并与预期的URL /有效载荷。如果调用三种方法不以任何显着的变化造成的,那么有没有什么你可以从一开始就进行测试,如此反复的事实,三种方法被称为按照一定的顺序变得无关紧要。
单元测试是有关验证该单位,没有什么更多的执行结果。现在,在命令式编程语言的输入 - >输出功能是少数,但是这并不意味着我们不能间接测试,如果函数的行为与预期。您可以使用模拟考试,或验证对象的某些属性,函数执行后。同样,如果没有外部检查的方法的顺序的方式,那么你有没有规范来验证。