2013-06-13 31 views
5

Tôi đang cố viết các bài kiểm tra đơn vị xung quanh việc triển khai SynchronizationContext tùy chỉnh.Làm cách nào để kiểm tra việc triển khai đồng bộ hoặc không đồng bộ khi được yêu cầu?

Hai hoạt động quan trọng trong lớp này là SendPost, trong đó Send gọi một đại biểu đồng bộ và Post gọi người được ủy quyền không đồng bộ.

Tôi muốn viết các bài kiểm tra đơn vị để xác minh hành vi này, rằng các đại biểu đã được thực hiện đồng bộ hoặc không đồng bộ. Tôi không muốn các bài kiểm tra dựa vào sự chậm trễ cho các trường hợp thành công, bởi vì nó kéo dài một cách giả tạo các thử nghiệm đang chạy (nhưng nó là hợp lý để có thất bại gây ra một sự chậm trễ) trong thực thi.

Ban đầu tôi đã xem xét sử dụng Công việc để báo hiệu việc thực hiện của một đại biểu:

var tcs = new TaskCompletionSource<object>(); 

var context = new CustomSynchronizationContext(); 

context.Send((state) => tcs.SetResult(null), null); 

// Task should already be completed! 
Assert.IsTrue(this.tcs.Task.IsCompleted); 

Tuy nhiên, điều này không đảm bảo các đại biểu đã được không thực hiện không đồng bộ rất nhanh chóng trước khi Á hậu kiểm tra có thể tiếp tục.

Làm thế nào tôi có thể sắp xếp một bài kiểm tra xung quanh bối cảnh để đảm bảo rằng Send khối cho việc hoàn thành các đại biểu và Post không, nhưng mà các đại biểu cả gọi?

+1

+1 cho câu hỏi và Tên "bi kịch" một người giải quyết vấn đề ... :) –

+0

ISN 't nó có thể làm một postback của 'Thread.ManagedThreadId' rằng các đại biểu thực hiện trên? Nếu nó giống như chủ đề chính, nó được thực thi đồng bộ, nếu không thì không đồng bộ. – Davio

+0

Ngữ cảnh đồng bộ hóa sẽ không chạy bất kỳ đại biểu nào trên chuỗi cuộc gọi, vì vậy tôi không sợ. Chỉ là một chi tiết thực hiện. –

Trả lời

-1

Kết hợp ý tưởng của tôi:

var mainThreadId = Thread.ManagedThreadId; 
var sendThreadId; 
context.Send((state) => sendThreadId = Thread.ManagedThreadId); 
Assert.AreEqual(mainThreadId, sendThreadId); 

Không biết nếu điều này thực sự hoạt động, bạn sẽ phải kiểm tra.

+0

Ngữ cảnh đồng bộ hóa sẽ không chạy bất kỳ đại biểu nào trên chuỗi cuộc gọi, vì vậy tôi không sợ. Chỉ là một chi tiết thực hiện trong lập trình không đồng bộ. –

+0

Vâng, “đồng bộ” và “không đồng bộ” không giống với “trên cùng một luồng” và “trên một chuỗi khác”. Phương thức đồng bộ có thể thực hiện ủy nhiệm trên một luồng khác và đợi đồng bộ để kết thúc. – svick

3

Tôi tin rằng bạn có thể đạt được điều này bằng cách sử dụng một cặp ManualResetEvents. Sử dụng đoạn mã dưới đây, tốc độ chậm chỉ là kinh nghiệm nếu các bài kiểm tra thất bại (các con số này khá cao và có thể có thể được giảm một cách an toàn). Ý tưởng ở đây là chúng tôi khẳng định thứ tự trong đó mọi thứ phải xảy ra mà chỉ có thể xảy ra nếu chúng ta chặn hoặc không chặn.

Đối với thử nghiệm đồng bộ:

var incall = new ManualResetEvent(false); 
var unblock = new ManualResetEvent(false); 
var context = new CustomSynchronizationContext(); 
var t = Task.Run(() => context.Send(state => 
{ 
    incall.Set(); 
    unblock.WaitOne(5000); 
}, null)); 
Assert.IsTrue(incall.WaitOne(1000)); 
Assert.IsFalse(t.Wait(10)); 
unblock.Set(); 
Assert.IsTrue(t.Wait(1000)); 

cho kỳ thi này Async:

var incall = new ManualResetEvent(false); 
var unblock = new ManualResetEvent(false); 
var context = new CustomSynchronizationContext(); 
var t = Task.Run(() =>context.Post(state => 
{ 
    incall.Set(); 
    unblock.WaitOne(5000); 
}, null)); 
Assert.IsTrue(incall.WaitOne(1000)); 
Assert.IsTrue(t.Wait(1000)); //This will timeout if unblock is blocking completion of the task 
unblock.Set(); 
+0

Nhưng một phương pháp không đồng bộ có thể vượt qua bài kiểm tra đồng bộ của bạn, nếu thời gian là đúng. – svick

+0

là bạn đề cập đến thực tế là việc bỏ chặn có thể hết thời gian chờ trước đó và tác vụ hoàn thành trước lần kiểm tra cuối cùng hoặc một số vấn đề khác? – jageall

+0

Không, trong phương thức 'Assert()' thứ hai, phương thức không đồng bộ có thể đã bắt đầu thực hiện (vì vậy 'incall.WaitOne()' hoàn thành ngay lập tức) nhưng cũng chưa trả về, vì vậy 'Trạng thái' sẽ vẫn là' Đang chạy'. – svick

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