我在Swift学习测试驱动开发。当我意识到我经常用于异步请求的委托模式很难测试时,我碰壁了。我已经了解到,如果某些事情难以测试,实施背后的设计模式可能会更好。这让我感到困惑,因为我认为我使用的代表模式很常见,我想知道其他人如何处理这个问题。
模式:
我编写了一个服务,它在一个带有委托实例的静态函数中执行异步请求。委托实例符合需要实现成功和失败方法的协议。我设计了一个打入Google.com的例子。请忽略此示例中的类型安全问题。我正在运行以命中端点并解析JSON的实际代码更安全。我只想提出一小段代码来描述在测试过程中造成困难的问题:
protocol GoogleServiceDelegate {
func gotGoogle(str: String);
func gotError(str: String);
}
struct GoogleService {
static func getGoogle(delegate: GoogleServiceDelegate) {
let url: NSURL! = NSURL(string: "http://google.com")
NSURLSession.sharedSession().dataTaskWithURL(url) { data, response, error in
if let data = data {
let str: NSString! = NSString(data: data, encoding: NSUTF8StringEncoding)
delegate.gotGoogle(str as String)
} else {
delegate.gotError("\(error)")
}
}
}
}
以下是说明问题的测试:
class AsyncTestingTests: XCTestCase {
func testExample() {
let responseExpectation = expectationWithDescription("Got google response!")
struct GoogleDelegate: GoogleServiceDelegate {
func gotGoogle(str: String) {
// expectations about response
responseExpectation.fulfill()
}
func gotError(str: String) {
// expectations about error
responseExpectation.fulfill()
}
}
let myGoogleServiceDelegate = GoogleDelegate()
GoogleService.getGoogle(myGoogleServiceDelegate)
waitForExpectationsWithTimeout(5) { _ in
print("Never got a response from Google :(")
}
}
}
问题出现在两条.fulfill()
行。我从Xcode收到以下错误:
结构声明不能超过价值' responseExpectation'在外部范围内定义
我理解错误,但我不确定要调整什么...有没有可以在测试中使用的解决方法,或者是否有比我正在尝试的异步回调更好(易于测试)的模式?如果你知道一个更好的可测试解决方案,你会介意花时间写下一个例子吗?
答案 0 :(得分:1)
是的,你不能关闭在struct之外定义的变量,为了解决方法,我们需要使用闭包/函数并将它传递给struct。 struct中的方法可以在收到响应时调用它。
func testExample() {
let responseExpectation = expectationWithDescription("Got google response!")
//Let a function capture the fulfilling of the expectation
func fullFillExpectation(){
responseExpectation.fullFill()
}
struct GoogleDelegate: GoogleServiceDelegate {
var fullFiller : (()->Void)!
func gotGoogle(str: String) {
// expectations about response via invoke the closure
fullFiller()
}
func gotError(str: String) {
// expectations about error - invoke the closure
fullFiller()
}
}
//Create the delegate with full filler function.
let myGoogleServiceDelegate = GoogleDelegate(fullFiller: fullFillExpectation)
GoogleService.getGoogle(myGoogleServiceDelegate)
waitForExpectationsWithTimeout(5) { _ in
print("Never got a response from Google :(")
}
}
}
PS:我无法测试,请测试并告诉我。