A simple introduction

  • The original liangdahong.com/2016/05/27/…

This article focuses on the use of XCTest

We know that unit testing is very important in program development, so without further ado, let’s get to it.

  1. When we create an Xcode project it will be created by default if we check it allXCTestDemoTests XCTestDemoUITestsThese two modules. Now I’m going to focus onXCTestDemoTestsThe use of. The template code is as follows:
// called before each test, which can be created before the testtest case// Put setup code here. This method is called before the Invocation of eachtest method in the class.
- (void)setUp {} // Call the tearDown method at the end of each invocation. This method is called after the Invocation of eachtest method inThe class. - (void)tearDown {} // We can add a custom - (void) testXXXX {} method, - (void)testxxx similar methods will automatically run when starting the test. // This is an example of a functionaltest case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
- (void)testExample {} // Test the performance of the method by testing the block execution time, compare the set standard value and deviation to see if the test can pass - (void)testPerformanceExample {
    // This is an example of a performance test case.
    [self measureBlock:^{
        // Put the code you want to measure the time of here.
    }];
}
Copy the code
  1. The use of XCTAssert. In unit testing, we usually use XCTAssert related methods, which are as follows:
// Universal assertion, fortrueBy testing XCTAssert(false); / / fortrueBy testing XCTAssertTrue(false); / / forfalseBy testing XCTAssertFalse(true); XCTAssertEqual(1, 2); XCTAssertNotEqual(0, 0); / / the value of the difference is within the range accuracy through test XCTAssertEqualWithAccuracy (10, 12, 1); / / passed test the value of the difference is beyond the scope of precision XCTAssertNotEqualWithAccuracy (10, 12, 1); XCTAssertNil(nil); // Pass XCTAssertNotNil(nil) without being nil; // Add XCTFail() to XCTFail(); XCTFail();Copy the code
  1. We can useTo launch all unit tests Toggle to the test module this depends on the version of XcodeOr use the following method to start the test:

  1. How do you write test cases?

For example, when we are developing a framework, we usually write some test cases. Let’s simulate writing a simple framework and write some test cases. For example, we’ll write a method to get the parameters in the URL.

The code is as follows:

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface NSString (BMURLParams)

@property (nonatomic, copy, readonly) NSDictionary *bm_URLParams; ///< URLParams

@end

NS_ASSUME_NONNULL_END
Copy the code
#import "NSString+BMURLParams.h"

@implementation NSString (BMURLParams)

- (NSDictionary *)bm_URLParams {
    NSRange range = [self rangeOfString:@"?"];
    if (range.location == NSNotFound) {
        return nil;
    }

    NSString *propertys = [self substringFromIndex:(range.location+1)];
    NSMutableDictionary *tempDic = @{}.mutableCopy;
    [[propertys componentsSeparatedByString:@"&"] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSArray *dicArray = [obj componentsSeparatedByString:@"="];
        if(dicArray.count > 1) { tempDic[dicArray[0]] = dicArray[1]; }}];return tempDic;
}

@end
Copy the code
  1. We implement the import in the XCTestDemoTests file#import "NSString+BMURLParams.h"At the same time add the following method:
- (void)test_URLParams {
    XCTAssert(@"https://www.baidu.com/s".bm_URLParams == nil);

     XCTAssert([(@"https://www.baidu.com/s?name=jck".bm_URLParams)
                isEqualToDictionary:(@{@"name" : @"jck"})]);

    XCTAssert([(@"https://www.baidu.com/s?name=jack&type=1".bm_URLParams)
                isEqualToDictionary:(@{@"name" : @"jack"The @"type" : @"1"})]);

    XCTAssert([(@"https://www.baidu.com/s?name=jack&type=1&user=80222".bm_URLParams)
                isEqualToDictionary:(@{@"name" : @"jack"The @"type" : @"1"The @"user" : @"80222"})]);

}
Copy the code
  • Run the test case and find the following effect

It means that all of our use cases have passed, and of course there are fewer use cases here, so we can add all kinds of possible cases. Now we deliberately miswrite the code to get the argument as follows:

#import "NSString+BMURLParams.h"

@implementation NSString (BMURLParams)

- (NSDictionary *)bm_URLParams {
    NSRange range = [self rangeOfString:@"?"];
    if (range.location == NSNotFound) {
        return nil;
    }

    NSString *propertys = [self substringFromIndex:(range.location+1)];
    NSMutableDictionary *tempDic = @{}.mutableCopy;
    [[propertys componentsSeparatedByString:@"&"] enumerateObjectsUsingBlock:^(NSString * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSArray *dicArray = [obj componentsSeparatedByString:@"="];
        if(dicArray.count > 1) { tempDic[dicArray[1]] = dicArray[0]; }}];return tempDic;
}
@end

Copy the code

Running a unit test should have the following effect:

The performance test

Now let’s simulate whether the return speed of the network interface matches our expectations and implement the class BMRequestManager that we create that should send network requests as follows:

@interface BMRequestManager : NSObject
+ (void)getDataWithSuccBlock:(dispatch_block_t)block;
@end
Copy the code
@implementation BMRequestManager + (void)getDataWithSuccBlock:(dispatch_block_t)block { Dispatch_after (dispatch_time(DISPATCH_TIME_NOW, dispatch_t)(6.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{! block ? : block(); }); } @endCopy the code
  • We write the test case code:
- (void)testExampleRequest {/ / 1, to create XCTestExpectation XCTestExpectation * exp = [self expectationWithDescription: @"This request is too slow."]; [BMRequestManager getDataWithSuccBlock:^{// Received data // send fulfill message [exp fulfill];}]; NSTimeInterval time = 15; //4, if the time exceeds XXX, error [self]waitForExpectationsWithTimeout:time handler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"Timeout Error: %@", error); }}]; }Copy the code

Since we set the expected time above to be 15 seconds, but we actually got the data in 6 seconds, use the following effect when we run the use case:

If we set the expected time to 5 seconds, the code looks like this:

- (void)testExampleRequest {/ / 1, to create XCTestExpectation XCTestExpectation * exp = [self expectationWithDescription: @"This request is too slow."]; [BMRequestManager getDataWithSuccBlock:^{// Received data // send fulfill message [exp fulfill];}]; NSTimeInterval time = 5.0; //4, if the time exceeds XXX, error [self]waitForExpectationsWithTimeout:time handler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"Timeout Error: %@", error); }}]; }Copy the code
  • Running a use case has the following effects:

Note The use case does not pass.

  • Of course, we can also test the execution time of some other code against the expected time to see if the code passes the expected time.

reference

  • Liuyanwei.jumppo.com/2016/03/10/…