[英]How can I ensure coverage of threaded code
我正在嘗試編寫一個單元測試,該測試可以100%地命中一段線程代碼來覆蓋代碼。 該代碼只能在線程應用程序的上下文中訪問,並且設計為每個對象實例僅被命中一次,以最大程度地減少鎖定時間。
作為簡化示例:
public class Example
{
private readonly object lockObject = new object();
private int? objectToInit = null;
public void EnsureObjectInit()
{
//To minimize hitting the lock code, the object is checked first.
if (!objectToInit.HasValue)
{
lock (lockObject)
{
//Then it is checked once more to ensure that it wasn't initiazlized
//before the lock was hit.
if (objectToInit.HasValue)
{
//This block can only be executed if a second thread is able to
//get to the lock before the first can initialize the object.
return;
}
objectToInit = 0;
}
}
}
}
為了獲得覆蓋第二個if語句中代碼的代碼,我嘗試了如下代碼:
[TestClass]
public class ExampleTest
{
[Test Method]
public void async MyTest()
{
Example example = new Example();
void runTask()
{
example.EnsureObjectInit();
}
//I've tried increasing the number of threads, but it doesn't make
//it hit the noted code any more consistently.
List<Task> tasks = new List<Task>(2);
tasks.Add(Task.Run(runTask));
tasks.Add(Task.Run(runTask));
await Task.WhenAll(tasks);
... perform extra validation ...
}
}
但是,如果至少有50%的時間阻塞,則代碼覆蓋率無法到達內部。
有什么方法可以強制經過單元測試的代碼在初始化對象之前停止第一個線程,以便第二個線程可以進入第一個“ if”塊?
有點lockObject
,但是您可以使用反射從Example類實例獲取lockObject
。 然后將其手動鎖定在ExampleTest方法中。 注意:這是一個高度耦合的測試。 如果更改鎖的名稱,則測試將失敗。
private class LockExample
{
private readonly object lockObject = new object();
public void TestLock()
{
lock(lockObject)
{
//Do something
}
}
}
private class LockTest
{
public void Test()
{
var example = new LockExample();
var lockOjbect = typeof(LockExample).GetField("lockObject", BindingFlags.NonPublic|BindingFlags.Instance).GetValue(example);
lock (lockOjbect)
{
var task = Task.Run((Action)example.TestLock);
task.Wait(1); //allow the other thread to run
}
}
}
有輕微的設計變更可以使你的代碼更可測試:提取訪問objectToInit.HasValue
成一個輔助方法類似hasObjectToInitValue()
在測試中,您可以覆蓋該方法,然后可以測試以下情況:助手方法在第一次調用時返回false
,在第二次調用時返回true
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.