在C#中引发事件的单元测试

Dav*_*all 151 c# events unit-testing

我有一些引发PropertyChanged事件的代码,我希望能够对事件正确引发的单元测试.

提升事件的代码就像

public class MyClass : INotifyPropertyChanged
{
   public event PropertyChangedEventHandler PropertyChanged;  

   protected void NotifyPropertyChanged(String info)
   {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(info));
        }
   }  

   public string MyProperty
   {
       set
       {
           if (_myProperty != value)
           {
               _myProperty = value;
               NotifyPropertyChanged("MyProperty");
           }
       }
   }
}
Run Code Online (Sandbox Code Playgroud)

我从单元测试中的以下代码中获得了一个很好的绿色测试,它使用了委托:

[TestMethod]
public void Test_ThatMyEventIsRaised()
{
    string actual = null;
    MyClass myClass = new MyClass();

    myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
    {
         actual = e.PropertyName;
    };

    myClass.MyProperty = "testing";
    Assert.IsNotNull(actual);
    Assert.AreEqual("MyProperty", actual);
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我然后尝试将属性的设置链接在一起,如下所示:

public string MyProperty
{
    set
    {
        if (_myProperty != value)
        {
            _myProperty = value;
            NotifyPropertyChanged("MyProperty");
            MyOtherProperty = "SomeValue";
        }
    }
}

public string MyOtherProperty
{
    set
    {
        if (_myOtherProperty != value)
        {
            _myOtherProperty = value;
            NotifyPropertyChanged("MyOtherProperty");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我对事件的测试失败 - 它捕获的事件是MyOtherProperty的事件.

我很确定事件会发生,我的UI会像它一样做出反应,但我的代表只捕获了最后一个事件.

所以我想知道:
1.我测试事件的方法是否正确?
我提高链式事件的方法是否正确?

And*_*ton 177

你所做的一切都是正确的,只要你想让你的测试问"最后发生的事件是什么?"

您的代码按此顺序触发这两个事件

  • 物业变更(......"我的财产"......)
  • 物业变更(......"MyOtherProperty"......)

这是否"正确"取决于这些事件的目的.

如果您想测试引发的事件数量以及引发它们的顺序,您可以轻松扩展现有测试:

[TestMethod]
public void Test_ThatMyEventIsRaised()
{
    List<string> receivedEvents = new List<string>();
    MyClass myClass = new MyClass();

    myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
    {
        receivedEvents.Add(e.PropertyName);
    };

    myClass.MyProperty = "testing";
    Assert.AreEqual(2, receivedEvents.Count);
    Assert.AreEqual("MyProperty", receivedEvents[0]);
    Assert.AreEqual("MyOtherProperty", receivedEvents[1]);
}
Run Code Online (Sandbox Code Playgroud)

  • 更短的版本:myClass.PropertyChanged + =(object sender,e)=> receivedEvents.Add(e.PropertyName); (10认同)

Tim*_*oyd 20

如果您正在进行TDD,那么事件测试可以开始生成大量重复代码.我编写了一个事件监视器,可以为这些情况提供更清晰的单元测试编写方法.

var publisher = new PropertyChangedEventPublisher();

Action test = () =>
{
    publisher.X = 1;
    publisher.Y = 2;
};

var expectedSequence = new[] { "X", "Y" };

EventMonitor.Assert(test, publisher, expectedSequence);
Run Code Online (Sandbox Code Playgroud)

有关详细信息,请参阅我对以下内容的回答.

使用反射测试在C#中引发事件的单元

  • 第二个链接已关闭. (3认同)

Sam*_*uel 10

这是非常古老的,可能甚至不会被阅读,但有一些很酷的新.net功能我创建了一个INPC Tracer类,允许:

[Test]
public void Test_Notify_Property_Changed_Fired()
{
    var p = new Project();

    var tracer = new INCPTracer();

    // One event
    tracer.With(p).CheckThat(() => p.Active = true).RaisedEvent(() => p.Active);

    // Two events in exact order
    tracer.With(p).CheckThat(() => p.Path = "test").RaisedEvent(() => p.Path).RaisedEvent(() => p.Active);
}
Run Code Online (Sandbox Code Playgroud)

请参阅要点:https://gist.github.com/Seikilos/6224204


Dam*_*Arh 6

下面是一个略微改变的安德鲁代码,而不是仅记录引发事件的序列,而是计算特定事件被调用的次数.虽然它是基于他的代码我发现它在我的测试中更有用.

[TestMethod]
public void Test_ThatMyEventIsRaised()
{
    Dictionary<string, int> receivedEvents = new Dictionary<string, int>();
    MyClass myClass = new MyClass();

    myClass.PropertyChanged += delegate(object sender, PropertyChangedEventArgs e)
    {
        if (receivedEvents.ContainsKey(e.PropertyName))
            receivedEvents[e.PropertyName]++;
        else
            receivedEvents.Add(e.PropertyName, 1);
    };

    myClass.MyProperty = "testing";
    Assert.IsTrue(receivedEvents.ContainsKey("MyProperty"));
    Assert.AreEqual(1, receivedEvents["MyProperty"]);
    Assert.IsTrue(receivedEvents.ContainsKey("MyOtherProperty"));
    Assert.AreEqual(1, receivedEvents["MyOtherProperty"]);
}
Run Code Online (Sandbox Code Playgroud)