C# 对事件进行单元测试

C# 对事件进行单元测试,c#,wpf,unit-testing,C#,Wpf,Unit Testing,我是C#和WPF的新手。我正在学习一个教程,我发现这段代码包含一个带有事件的单元测试。你能给我解释一下吗: [TestClass] class ObservableObjectTests { [TestMethod] public void PropertyChangedEventHandlerIsRaised() { var obj = new SubObservableObject(); bool raised = false;

我是C#和WPF的新手。我正在学习一个教程,我发现这段代码包含一个带有事件的单元测试。你能给我解释一下吗:

[TestClass]
class ObservableObjectTests
{
    [TestMethod]
    public void PropertyChangedEventHandlerIsRaised()
    {
        var obj = new SubObservableObject();

        bool raised = false;

        obj.PropertyChanged += (Sender, e) =>
            {
                Assert.IsTrue(e.PropertyName == "ChangedProperty");
                raised = true;

            };
    }
}

正如@Scott Chamberlain在评论中所说的,您的示例代码并不代表真正的测试用例。最低测试用例如下所示:

[TestClass]
public class ObservableObjectTests {
    [TestMethod]
    public void PropertyChangedEventHandlerIsRaised() {
        // Create the object to test (sut)
        var sut = new SubObservableObject();

        //  Create a flag to monitor if event handler has fired
        //  set it to false initially, since it hasn't...
        bool raised = false;

        // Register our test event handler, with the PropertyChanged
        // event.
        sut.PropertyChanged += (Sender, e) => {
                // Check that when the event handler is called
                // it is for the 'ChangedProperty'
                Assert.IsTrue(e.PropertyName == "ChangedProperty");
                // Set our flag to indicate that event was triggered
                raised = true;
            };

        // Actually perform the test, by setting 'ChangedProperty' to 
        // a new value.  This will fire the code above if it works.
        sut.ChangedProperty = "newValue";

        // Validate that our raised flag has been set to true, indicating
        // that our test event handler was triggered.
        Assert.AreEqual(true, raised);
    }
}
public class SubObservableObject : INotifyPropertyChanged {
    public string ChangedProperty {
        get { return _changedProperty; }
        set {
            _changedProperty = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ChangedProperty" ));
        }
    }

    public string _changedProperty;

    public event PropertyChangedEventHandler PropertyChanged;
};
请注意,为了使上述工作正常进行,我对正在测试的代码做了大量假设。本质上,我假设正在测试的代码看起来很像这样:

[TestClass]
public class ObservableObjectTests {
    [TestMethod]
    public void PropertyChangedEventHandlerIsRaised() {
        // Create the object to test (sut)
        var sut = new SubObservableObject();

        //  Create a flag to monitor if event handler has fired
        //  set it to false initially, since it hasn't...
        bool raised = false;

        // Register our test event handler, with the PropertyChanged
        // event.
        sut.PropertyChanged += (Sender, e) => {
                // Check that when the event handler is called
                // it is for the 'ChangedProperty'
                Assert.IsTrue(e.PropertyName == "ChangedProperty");
                // Set our flag to indicate that event was triggered
                raised = true;
            };

        // Actually perform the test, by setting 'ChangedProperty' to 
        // a new value.  This will fire the code above if it works.
        sut.ChangedProperty = "newValue";

        // Validate that our raised flag has been set to true, indicating
        // that our test event handler was triggered.
        Assert.AreEqual(true, raised);
    }
}
public class SubObservableObject : INotifyPropertyChanged {
    public string ChangedProperty {
        get { return _changedProperty; }
        set {
            _changedProperty = value;
            PropertyChanged(this, new PropertyChangedEventArgs("ChangedProperty" ));
        }
    }

    public string _changedProperty;

    public event PropertyChangedEventHandler PropertyChanged;
};
正如在评论中提到的,这是一个最低限度的示例代码,可以让您要求的测试正常工作。您正在学习的教程应该有额外的测试来帮助验证它们的代码。下面的测试足以强制测试PropertyChanged事件是否为null

[TestMethod]
public void PropertyCanChangeWithNoEventHandlersSet() {
    var sut = new SubObservableObject();

    // The next line will throw a null exception with the minimal
    // code written above, since there is no check for 
    // if(null != PropertyChanged) before invoking the PropertyChanged
    // event.
    sut.ChangedProperty = "newValue";

    Assert.AreEqual("newValue", sut.ChangedProperty);
}
在实际的代码库中,很可能已将此检查和调用重新分解为从类中的所有属性调用的单个函数

根据目标C#的版本,此方法也可能自动检测正在更改的属性的名称,从而不必显式提供。这将导致这样的代码

通过每个单独的属性调用此方法:

public string ChangedProperty {
    get { return _changedProperty; }
    set {
            _changedProperty = value;
            NotifyPropertyChanged();
        }
}

那代码不完整。您从未更改测试中的属性,因此测试不会执行任何操作。谢谢您,我会考虑这些内容谢谢@ScottChamberlain,我已使用您的反馈修改了预期的代码,以使其更简单。虽然可以说这是一个很好的答案,但您可以说花了更多的精力解释了什么是
SubObservableObject
(测试中的代码;由于OP没有发布任何代码,这在某种程度上是假设性的),而不是按照OP的问题“我在遵循教程,我发现了包含带有事件的单元测试的代码,您能解释给我看吗?”但是,我同意OP的问题是不完整的,其中可能存在问题。代码注释很好,但可能用简单的英语解释了单元测试块。祝你好运!事实上,我下面的教程包含不止一个示例。只是我对事件感到不安。谢谢