2015-01-21 18 views
11

Tôi đã viết một số kiểm tra đơn vị không đồng bộ với XCTest các kỳ vọng để kiểm tra lớp mạng tôi đã viết. Hầu hết các bài kiểm tra của tôi làm việc mọi lúc.Kiểm tra Xcode được tách biệt, thất bại khi chạy với các thử nghiệm khác

Có một vài thử nghiệm không thành công khi tôi chạy toàn bộ bộ, nhưng tự mình vượt qua.

Các kiểm tra khác không thành công, nhưng việc đưa ra các yêu cầu có cùng URL trả lại dữ liệu thích hợp khi được dán vào trình duyệt.

Mã mạng của tôi được đóng gói trong NSOperation các đối tượng được chạy trên NSOperationQueue. (Hàng đợi hoạt động của tôi là loại mặc định - tôi chưa rõ ràng đặt hàng đợi GCD cơ bản để nối tiếp hoặc đồng thời.)

Tôi có thể xem xét để khắc phục những thử nghiệm này? Sau khi đọc this post on objc.io, tôi giả định rằng họ đang bị một số vấn đề cách ly.

Trả lời

8

Bạn đang đi đúng hướng. Các giải pháp được đề xuất bởi bài viết objc.io có lẽ là The Way Right để làm điều đó nhưng không yêu cầu một số refactoring. Nếu bạn muốn làm cho các bài kiểm tra diễn ra như một bước đầu tiên trước khi bạn đi vào một thay đổi mã binge, đây là cách bạn có thể làm điều đó.

Thông thường, bạn có thể sử dụng XCTestExpectations để thực hiện gần như tất cả các thử nghiệm không đồng bộ của bạn. Một mô hình tiêu chuẩn có thể đi như thế này:

XCTestExpectation *doThingPromise = [self expetationWithDescription:@"Bazingo"]; 
[SomeService doThingOnSucceed:^{ 
    [doThingPromise fulfill]; 
} onFail:^ { 
}]; 
[self waitForExpectationsWithTimeout:1.0 handler:^(NSError *error) { 
    expect(error).to.beNil(); 
}] 

này hoạt động tốt nếu [SomeService doThingOnSucceed: onFail:] cháy ra một yêu cầu async và sau đó giải quyết trực tiếp. Nhưng nếu nó làm những điều kỳ lạ hơn như:

+ (void)doThingOnSucceed:onFail: { 
    [Thing do it]; 
    [self.context performBlock:^{ 
    // Uh oh Farfalle-Os 
    success(); 
    }]; 
} 

Khối thực hiện sẽ được thiết lập nhưng bạn sẽ không chờ đợi để hoàn thành vì bạn không thực sự chờ đợi khối bên trong, chỉ bên ngoài một. Điều quan trọng là XCTestWaits thực sự cho phép kết thúc kiểm tra và sau đó chỉ kiểm tra rằng lời hứa đã được thực hiện trong một khoảng thời gian nhưng trong thời gian đó nó sẽ bắt đầu chạy các thử nghiệm khác. Thành công đó() có thể xuất hiện bất kỳ số lượng địa điểm nào và tạo ra bất kỳ số lượng hành vi kỳ lạ nào.

Hành vi cách ly (không có cách ly) xuất phát từ thực tế là nếu bạn chỉ chạy thử nghiệm này, mọi thứ có thể tốt do may mắn nhưng nếu bạn chạy nhiều thử nghiệm thì khối CoreData có thể bị treo xung quanh cho đến khi thử nghiệm tiếp theo là không đồng bộ, sau đó sẽ "bỏ chặn" thực thi của nó và nó sẽ bắt đầu thực hiện tại một số thời gian tương lai ngẫu nhiên cho một số thử nghiệm ngẫu nhiên trong tương lai.

Tấn công ngắn hạn rõ ràng xung quanh là tạm dừng thử nghiệm của bạn cho đến khi mọi thứ kết thúc. Dưới đây là một ví dụ:

dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 
[SomeService doThingOnComplete:^{ 
    dispatch_semaphore_signal(semaphore); 
}]; 
while (dispatch_semaphore_wait(semaphore, DISPATCH_TIME_NOW)) { 
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:10]]; 
} 

Điều này ngăn cản một cách rõ ràng kiểm tra từ hoàn thành cho đến khi mọi thứ kết thúc, có nghĩa là không xét nghiệm khác có thể chạy cho đến khi kiểm tra này kết thúc.

Nếu có rất nhiều trường hợp trong các bài kiểm tra/mã của bạn, tôi khuyên bạn nên sử dụng giải pháp objc.io để tạo nhóm công văn mà bạn có thể đợi sau mỗi lần kiểm tra.

+0

Đang cố gắng để thực hiện điều này (trong Swift) và tôi thấy rằng nó hoạt động, nhưng nó không tiếp tục ngay sau khi tín hiệu semaphore. Nó treo trên Runloop.run cho đến khi thời gian chờ xảy ra. Đây có phải là dự kiến ​​không? Mã của tôi: 'trong khi semaphore.wait (thời gian chờ: .now()) == .timedOut { RunLoop.current.run (cho đến: Ngày (timeIntervalSinceNow: 10)) }' – guptron

1

Sau khi chiến đấu NSOperationQueue và trở lại có vẻ không chính xác từ waitUntilAllOperationsAreFinished trong một vài ngày tôi đã nhấn vào một tùy chọn đơn giản hơn: phân vùng thử nghiệm của bạn thành nhiều mục tiêu thử nghiệm. Điều này cho phép bạn kiểm tra môi trường 'ứng dụng' của riêng mình và quan trọng hơn trong trường hợp này, đảm bảo Xcode/XCUnit sẽ chạy chúng tuần tự để chúng không thể can thiệp vào nhau - trừ khi chúng làm những việc như để cơ sở dữ liệu bị bẩn (có thể là một thất bại anyway).

Cách nhanh nhất để thực hiện việc này là sao chép mục tiêu thử nghiệm của bạn, xóa các kiểm tra không thành công khỏi bản gốc và xóa mọi thứ ngoại trừ các thử nghiệm không thành công của bạn khỏi mục tiêu mới. Lưu ý rằng nếu bạn có nhiều thử nghiệm can thiệp vào nhau, bạn cần nhiều mục tiêu để đạt được sự cô lập đủ.

Extra targets

Bạn có thể kiểm tra xem các bài kiểm tra được thực hiện bằng cách kiểm tra các chương trình mục tiêu thử nghiệm. Trong chương trình, bạn sẽ thấy cả hai (tất cả) mục tiêu thử nghiệm của bạn và bên dưới chúng là các thử nghiệm riêng lẻ của bạn.

Scheme editor

Các vấn đề liên quan