Testable asynchronous design pattern in Swift

I am learning Test Driven Development in Swift. I hit the wall when I realized that the delegate pattern that I regularly use for asynchronous requests is hard to verify. I learned that if something is difficult to test, the design of an implementation scheme might be better. This is confusing to me because I think the delegate template I use is shared, and I wonder how others handled this problem.

Sample:

I wrote a service that executes an asynchronous request in a static function that accepts a delegate instance. The delegate instance conforms to a protocol that requires the implementation of a success and failure method. I came up with an example that lands on Google.com. In this example, ignore type security issues. The actual code that I run to get to the endpoint and parse the JSON is safer. I just wanted to come up with a very small piece of code to portray a problem causing testing difficulties:

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)")
            }
        }
    }
}

Here is a test that illustrates the problem:

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 :(")
        }
    }
}

The problem occurs in two lines .fulfill(). I get the following error from Xcode:

Structure declaration cannot close the value of "responseExpectation" defined in the outer scope

, , ... , , ( ) , , ? , , ?

+4
1

, , , , / . 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: , , .

+1

Source: https://habr.com/ru/post/1624210/


All Articles