Skip to content

Latest commit

 

History

History
134 lines (100 loc) · 3.74 KB

UnitTest.md

File metadata and controls

134 lines (100 loc) · 3.74 KB

单元测试

借助于使用接口管理依赖的方案,我们在对模块进行单元测试时,可以自由配置 mock 依赖,而且无需 hook 模块内部的代码。

例如这样一个依赖于网络模块的登陆模块:

// 登录模块
class LoginService {

    func login(account: String, password: String, completion: (Result<LoginError>) -> Void) {
        // 内部使用 RequiredNetServiceInput 进行网络访问
        let netService = Router.makeDestination(to: RoutableService<RequiredNetServiceInput
        >())
        let request = makeLoginRequest(account: account, password: password)
        netService?.POST(request: request, completion: completion)
    }
}

// 声明依赖
extension RoutableService where Protocol == RequiredNetServiceInput {
    init() {}
}
Objective-C Sample
// 登录模块
@interface LoginService : NSObject
@end
@implementation LoginService

- (void)loginWithAccount:(NSString *)account password:(NSString *)password  completion:(void(^)(Result *result))completion {
    // 内部使用 RequiredNetServiceInput 进行网络访问
    id<RequiredNetServiceInput> netService = [ZIKRouterToService(RequiredNetServiceInput) makeDestination];
    Request *request = makeLoginRequest(account, password);
    [netService POSTRequest:request completion: completion];
}

@end
  
// 声明依赖
@protocol RequiredNetServiceInput <ZIKServiceRoutable>
- (void)POSTRequest:(Request *)request completion:(void(^)(Result *result))completion;
@end

在编写单元测试时,不需要引入真实的网络模块,可以提供一个自定义的 mock 网络模块:

class MockNetService: RequiredNetServiceInput {
    func POST(request: Request, completion: (Result<NetError>) {
        completion(.success)
    }
}
// 注册 mock 依赖
ZIKAnyServiceRouter.register(RoutableService<RequiredNetServiceInput>(), 
                 forMakingService: MockNetService.self) { (config, router) -> EditorViewProtocol? in
                     return MockNetService()
        }
Objective-C Sample
@interface MockNetService : NSObject <RequiredNetServiceInput>
@end
@implementation MockNetService

- (void)POSTRequest:(Request *)request completion:(void(^)(Result *result))completion {
    completion([Result success]);
}
  
@end
// 注册 mock 依赖
[ZIKServiceRouter registerServiceProtocol:ZIKRoutable(EditorViewInput) forMakingService:[MockNetService class]];

对于那些没有接口交互的外部依赖,例如只是简单的跳转到对应界面,则只需注册一个空白的 proxy。

单元测试代码:

class LoginServiceTests: XCTestCase {
    
    func testLoginSuccess() {
        let expectation = expectation(description: "end login")
        
        let loginService = LoginService()
        loginService.login(account: "account", password: "pwd") { result in
            expectation.fulfill()
        }
        
        waitForExpectations(timeout: 5, handler: { if let error = $0 {print(error)}})
    }
    
}
Objective-C Sample
@interface LoginServiceTests : XCTestCase
@end
@implementation LoginServiceTests

- (void)testLoginSuccess {
    XCTestExpectation *expectation = [self expectationWithDescription:@"end login"];
    
    [[LoginService new] loginWithAccount:@"" password:@"" completion:^(Result *result) {
        [expectation fulfill];
    }];
    
    [self waitForExpectationsWithTimeout:5 handler:^(NSError * _Nullable error) {
        !error? : NSLog(@"%@", error);
    }];
}
@end

使用接口管理依赖,可以更容易 mock,剥除外部依赖对测试的影响,让单元测试更稳定。