Tôi đang viết kiểm tra đơn vị cho lớp "keo" của ứng dụng và đang gặp khó khăn khi tạo các phép thử xác định cho các phương pháp không đồng bộ cho phép người dùng hủy hoạt động sớm.Hủy hòa nhạc trong thử nghiệm đơn vị dài
Cụ thể, trong một vài phương pháp không đồng bộ, chúng tôi có mã phản ứng với việc hủy cuộc gọi và đảm bảo rằng đối tượng ở trạng thái thích hợp trước khi hoàn thành. Tôi muốn đảm bảo rằng các đường dẫn mã này được kiểm tra.
Một số C# pseudo code khuôn mẫu cho một phương pháp async điển hình trong trường hợp này là như sau:
public void FooAsync(CancellationToken token, Action<FooCompletedEventArgs> callback)
{
if (token.IsCancellationRequested) DoSomeCleanup0();
// Call the four helper methods, checking for cancellations in between each
Exception encounteredException;
try
{
MyDependency.DoExpensiveStuff1();
if (token.IsCancellationRequested) DoSomeCleanup1();
MyDependency.DoExpensiveStuff2();
if (token.IsCancellationRequested) DoSomeCleanup2();
MyDependency.DoExpensiveStuff3();
if (token.IsCancellationRequested) DoSomeCleanup3();
MyDependency.DoExpensiveStuff4();
if (token.IsCancellationRequested) DoSomeCleanup4();
}
catch (Exception e)
{
encounteredException = e;
}
if (!token.IsCancellationRequested)
{
var args = new FooCompletedEventArgs(a bunch of params);
callback(args);
}
}
Các giải pháp mà tôi đã đưa ra cho đến nay liên quan đến chế giễu những tiềm ẩn MyDependency
hoạt động được bao bọc bởi lớp keo và buộc mỗi người phải ngủ trong một khoảng thời gian tùy ý. Sau đó tôi gọi phương thức async và cho phép kiểm tra đơn vị của tôi ngủ trong một số mili giây trước khi hủy yêu cầu không đồng bộ.
Something như thế này (sử dụng Rhino Mocks là một ví dụ):
[TestMethod]
public void FooAsyncTest_CancelAfter2()
{
// arrange
var myDependency = MockRepository.GenerateStub<IMyDependency>();
// Set these stubs up to take a little bit of time each so we can orcestrate the cancels
myDependency.Stub(x => x.DoExpensiveStuff1()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff2()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff3()).WhenCalled(x => Thread.Sleep(100));
myDependency.Stub(x => x.DoExpensiveStuff4()).WhenCalled(x => Thread.Sleep(100));
// act
var target = new FooClass(myDependency);
CancellationTokenSource cts = new CancellationTokenSource();
bool wasCancelled = false;
target.FooAsync(
cts.Token,
args =>
{
wasCancelled = args.IsCancelled;
// Some other code to manipulate FooCompletedEventArgs
});
// sleep long enough for two operations to complete, then cancel
Thread.Sleep(250);
cts.Cancel();
// Some code to ensure the async call completes goes here
//assert
Assert.IsTrue(wasCancelled);
// Other assertions to validate state of target go here
}
Bên cạnh thực tế rằng việc sử dụng Thread.Sleep trong một thử nghiệm đơn vị làm cho tôi buồn nôn, vấn đề lớn hơn là thỉnh thoảng kiểm tra như thế này không trên máy chủ xây dựng của chúng tôi nếu nó xảy ra dưới tải trọng đáng kể. Cuộc gọi async bị quá xa và quá trình hủy đến quá muộn.
Có ai có thể cung cấp một cách đáng tin cậy hơn về logic hủy kiểm tra đơn vị cho các hoạt động chạy dài như thế này không? Có những câu chuyện mới trên trang chủ.
Điều này trông cực kỳ hứa hẹn. Tôi sẽ thử nó vào chiều nay, và sẽ báo cáo lại. –
Nó hoạt động rất tốt. Cảm ơn bạn đã giúp đỡ! –