Xcode 6 asynchronous test <transcription>

Source: Internet
Author: User

In 2013, Apple launched an xcode test framework called xctest, which is quite popular. Some third-party testing tools and testing frameworks compete to provide many new functions and features, as the old test framework has been updated for several years. The decision to build xctest in xcode allows developers to regain their old preferences. Apple also added several previously missed features in xcode 6 this year, the asynchronous test feature in this process makes me even more excited.

If an asynchronous task is to be executed in our test project, it may run in other threads or in the runloop of the main thread, in this case, how should we perform the test?

Assume that the function of a Web request needs to be tested. We will start the Web request and enter the blocking, and then make a test assertion in the code block completed by the program. However, since there is no Web request, let alone the response, we need to ensure that the test method is being executed before asserted to call the code that completes part of the program.

Next, let's take a test of downloading web pages. In general, we do not actually perform Web response during testing, but use some tools to interrupt the response (such as my favorite ohhttpstubs ). However, in the following example, we need to change the rule-to complete a web response for testing.

We use a URL and a program completion block to test this class. It downloads the page indicated by the URL and calls this program block. If it succeeds, it will get a string containing the web page, when an error occurs, it is an empty string.

12345678910111213141516 - (void)testCodeYouShouldNeverWrite    {        __block NSString *pageContents = nil;                 [self.pageLoader requestUrl:@"http://bignerdranch.com"                  completionHandler:^(NSString *page) {                               NSLog(@"The web page is %ld bytes long.", page.length);            pageContents = page;            // Test method ends before this test assertion is called            XCTAssert(pageContents.length > 0);         }];                 // Nothing prevents the test method from returning before         // completionHandler is called.    }

In versions earlier than xcode 6, there is no built-in xctest. To test with xcode, you can only use a while loop in the runloop of the main thread, and then wait for the response or wait until timeout, the code for this old method is as follows:

123456789101112131415161718192021 - (void)testAsyncTheOldWay    {        NSDate *timeoutDate = [NSDate dateWithTimeIntervalSinceNow:5.0];        __block BOOL responseHasArrived = NO;             [self.pageLoader requestUrl:@"http://bignerdranch.com"                  completionHandler:^(NSString *page) {                               NSLog(@"The web page is %ld bytes long.", page.length);            responseHasArrived = YES;            XCTAssert(page.length > 0);        }];             while (responseHasArrived == NO && ([timeoutDate timeIntervalSinceNow] > 0)) {            CFRunLoopRunInMode(kCFRunLoopDefaultMode, 0.01, YES);        }             if (responseHasArrived == NO) {            XCTFail(@"Test timed out");        }    }

This while loop runs every 10 milliseconds in the main thread until a response is received or 5 seconds later than the response time limit is exceeded. This method is very effective and does not look bad, but it does not mean the end of development-this method is still not good enough.
Next we will discuss a more optimized approach.
High expectation (High expectations)

In xcode 6, Apple added test expectation to the xctest framework in the form of xctestexpection class ). When we instantiate a test expectation (xctestexpectation), the test framework expects it to be implemented at a later time. The test code in the final program completion code block calls the fulfill method in the xctestexpection class to implement the expectation. This method replaces the method in the previous example that uses responsehasarrived as the flag. In this case, let the test framework wait (with a time limit) to test the expected result through the waitforexpectationswithtimeout: Handler: Method of xctestcase. If the code that completes the processing is executed within the specified time limit and the fulfill method is called, all test expectations are implemented during this period. Otherwise, this test will be a tragedy, and it will be silently stored in the program and won't be implemented even once ......

Of course, the failure result does not mean a failed test. Only the test results in the unknown are considered as failed tests.
The following is an example of using xctestexpection:

123456789101112131415161718 (void)testWebPageDownload    {        XCTestExpectation *expectation =            [self expectationWithDescription:@"High Expectations"];        [self.pageLoader requestUrl:@"http://bignerdranch.com"                  completionHandler:^(NSString *page) {                               NSLog(@"The web page is %ld bytes long.", page.length);            XCTAssert(page.length > 0);            [expectation fulfill];        }];             [self waitForExpectationsWithTimeout:5.0 handler:^(NSError *error) {            if (error) {                NSLog(@"Timeout Error: %@", error);            }        }];    }

Output some information in the test expectation to enhance the readability of the test results. Use [expectation fulfill] In the final code segment to inform you that the expected part of the test has been implemented. Then, use the waitforexpectationswithtimeout: Handler method to wait for a response. The response will be executed after the response is received ...... Or it will be executed after timeout.
The implementation in OC is good. In addition, we can also implement this test in swift:

1234567891011121314 func testWebPageDownload() {                 let expectation = expectationWithDescription("Swift Expectations")                 self.pageLoader.requestUrl("http://bignerdranch.com", completion: {            (page: String?) -> () in            if let downloadedPage = page {                XCTAssert(!downloadedPage.isEmpty, "The page is empty")                expectation.fulfill()            }        })                 waitForExpectationsWithTimeout(5.0, handler:nil)    }

 

(This article is translated by cocoachina. For more information, see the source .)

Xcode 6 asynchronous test <transcription>

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.