Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/337.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何确保线程代码的覆盖率_C#_Multithreading_Unit Testing_Code Coverage_Mstest - Fatal编程技术网

C# 如何确保线程代码的覆盖率

C# 如何确保线程代码的覆盖率,c#,multithreading,unit-testing,code-coverage,mstest,C#,Multithreading,Unit Testing,Code Coverage,Mstest,我正在尝试编写一个单元测试,它可以100%地命中一段线程代码,从而实现代码覆盖率。代码只能在线程化应用程序的上下文中访问,并且设计为每个对象实例只命中一次,以最小化锁定时间开销 作为一个简化的例子: public class Example { private readonly object lockObject = new object(); private int? objectToInit = null; public void EnsureObjectInit() {

我正在尝试编写一个单元测试,它可以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块


有没有办法强制单元测试代码在初始化对象之前停止第一个线程,以便第二个线程可以进入第一个if块?

这有点麻烦,但是您可以使用反射从示例类实例获取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的帮助器方法中。在测试中,您可以覆盖该方法,然后测试第一次调用的helper方法返回false,第二次调用的helper方法返回true的场景。

是否可以模拟它以确保覆盖所需的代码位?好主意。我要做的唯一更改是在任务上使用Wait关键字,而不是任务的Wait函数。可能只是语义上的,但“await”将阻止当前线程,直到任务完成,这可能会导致死锁。Wait1只是停止当前线程足够长的时间,让另一个线程启动并被锁阻塞。