Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/263.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# 使用nunit测试事件_C#_Unit Testing_Events_Nunit_C# 2.0 - Fatal编程技术网

C# 使用nunit测试事件

C# 使用nunit测试事件,c#,unit-testing,events,nunit,c#-2.0,C#,Unit Testing,Events,Nunit,C# 2.0,我刚开始使用TDD,可以自己解决我所面临的大多数问题。但现在我迷路了:如何检查事件是否被触发?我在寻找类似于Assert.Raise或Assert.Fire的东西,但什么都没有。谷歌不是很有用,大多数点击都是建议,比如foo.myEvent+=neweventhandler(bar);Assert.NotNull(foo.myEvent)t.Name=null); t、 Name=“测试”; 断言(e,Event.isnotrised(),()=>t.Name=“test”); } [测试] 公

我刚开始使用TDD,可以自己解决我所面临的大多数问题。但现在我迷路了:如何检查事件是否被触发?我在寻找类似于
Assert.Raise
Assert.Fire
的东西,但什么都没有。谷歌不是很有用,大多数点击都是建议,比如
foo.myEvent+=neweventhandler(bar);Assert.NotNull(foo.myEvent)

谢谢大家!

您可以添加自定义事件处理程序,例如,在测试用例类中增加一些整数字段。然后检查字段是否递增。

可以通过订阅该事件并设置布尔值来检查是否触发了事件:

var wasCalled = false;
foo.NyEvent += (o,e) => wasCalled = true;

...

Assert.IsTrue(wasCalled);
根据要求-无lambdas:

var wasCalled = false;
foo.NyEvent += delegate(o,e){ wasCalled = true;}

...

Assert.IsTrue(wasCalled);

我自己并没有这样做,但也许你可以给你想要订阅的事件添加一个虚拟事件处理程序,让它更新一个局部布尔变量,这样在方法被激发后,你就可以检查布尔值的状态,看看事件是否被激发了

比如:

bool eventFired = false;
foo.MyEvent += (s, e) => { eventFired = true };

Assert.IsTrue(eventFired);
@燃烧和尚:一个“;”不见了。更正版本为:

bool eventFired = false;
foo.MyEvent += (s, e) => { eventFired = true; };
Assert.IsTrue(eventFired);

干杯

我最近不得不这么做,下面是我的想法。我之所以没有像其他帖子所说的那样做,是因为我不喜欢变量保持状态并在多个事件之间“手动”重置它的想法

下面是在
MyTests
测试中测试的
ClassUnderTest
带有
NameChanged
事件的代码:

public class ClassUnderTest {
    private string name;
    public string Name {
        get { return this.name; }
        set {
            if (value != this.name) {
                this.name = value;
                NameChanged(this, new PropertyChangedEventArgs("Name"));
            }
        }
    }

    public event EventHandler<PropertyChangedEventArgs> NameChanged = delegate { };
}

[TestFixture]
public class MyTests {
    [Test]
    public void Test_SameValue() {
        var t = new ClassUnderTest();
        var e = new EventHandlerCapture<PropertyChangedEventArgs>();
        t.NameChanged += e.Handler;

        Event.Assert(e, Event.IsNotRaised<PropertyChangedEventArgs>(), () => t.Name = null);
        t.Name = "test";
        Event.Assert(e, Event.IsNotRaised<PropertyChangedEventArgs>(), () => t.Name = "test");
    }
    [Test]
    public void Test_DifferentValue() {
        var t = new ClassUnderTest();
        var e = new EventHandlerCapture<PropertyChangedEventArgs>();
        t.NameChanged += e.Handler;

        Event.Assert(e, Event.IsPropertyChanged(t, "Name"), () => t.Name = "test");
        Event.Assert(e, Event.IsPropertyChanged(t, "Name"), () => t.Name = null);
    }
}
测试中的公共类{
私有字符串名称;
公共字符串名{
获取{返回this.name;}
设置{
if(值!=此.name){
this.name=值;
名称变更(这是新的PropertyChangedEventArgs(“名称”);
}
}
}
public event EventHandler NameChanged=委托{};
}
[测试夹具]
公共类MyTests{
[测试]
公共无效测试_SameValue(){
var t=新类未测试();
var e=新的EventHandlerCapture();
t、 NameChanged+=e.Handler;
断言(e,Event.isnotrised(),()=>t.Name=null);
t、 Name=“测试”;
断言(e,Event.isnotrised(),()=>t.Name=“test”);
}
[测试]
公共无效测试_差异值(){
var t=新类未测试();
var e=新的EventHandlerCapture();
t、 NameChanged+=e.Handler;
断言(e,Event.IsPropertyChanged(t,“Name”),()=>t.Name=“test”);
断言(e,Event.IsPropertyChanged(t,“Name”),()=>t.Name=null);
}
}
支持课程如下。这些类可以与任何
EventHandler
一起使用,也可以扩展到其他委托。事件测试可以嵌套

/// <summary>Class to capture events</summary>
public class EventHandlerCapture<TEventArgs> where TEventArgs : EventArgs {
    public EventHandlerCapture() {
        this.Reset();
    }

    public object Sender { get; private set; }
    public TEventArgs EventArgs { get; private set; }
    public bool WasRaised { get; private set; }

    public void Reset() {
        this.Sender = null;
        this.EventArgs = null;
        this.WasRaised = false;
    }

    public void Handler(object sender, TEventArgs e) {
        this.WasRaised = true;
        this.Sender = sender;
        this.EventArgs = e;
    }
}

/// <summary>Contains things that make tests simple</summary>
public static class Event {
    public static void Assert<TEventArgs>(EventHandlerCapture<TEventArgs> capture, Action<EventHandlerCapture<TEventArgs>> test, Action code) where TEventArgs : EventArgs {
        capture.Reset();
        code();
        test(capture);
    }
    public static Action<EventHandlerCapture<TEventArgs>> IsNotRaised<TEventArgs>() where TEventArgs : EventArgs {
        return (EventHandlerCapture<TEventArgs> test) => {
            NUnit.Framework.Assert.That(test.WasRaised, Is.False);
        };
    }
    public static Action<EventHandlerCapture<PropertyChangedEventArgs>> IsPropertyChanged(object sender, string name) {
        return (EventHandlerCapture<PropertyChangedEventArgs> test) => {
            NUnit.Framework.Assert.That(test.WasRaised, Is.True);
            NUnit.Framework.Assert.That(test.Sender, Is.SameAs(sender));
            NUnit.Framework.Assert.That(test.EventArgs.PropertyName, Is.EqualTo(name));
        };
    }
}
///用于捕获事件的类
公共类EventHandlerCapture,其中TEventArgs:EventArgs{
publicEventHandlerCapture(){
这是Reset();
}
公共对象发送方{get;private set;}
public TEventArgs EventArgs{get;private set;}
已引发公共布尔{get;private set;}
公共无效重置(){
this.Sender=null;
this.EventArgs=null;
this.wasrised=false;
}
公共无效处理程序(对象发送方,TEventArgs e){
this.wasrised=true;
this.Sender=Sender;
this.EventArgs=e;
}
}
///包含使测试变得简单的内容
公共静态类事件{
公共静态void断言(EventHandlerCapture捕获、操作测试、操作代码),其中TEventArgs:EventArgs{
capture.Reset();
代码();
测试(捕获);
}
公共静态操作未引发(),其中TEventArgs:EventArgs{
返回(EventHandlerCapture测试)=>{
NUnit.Framework.Assert.That(test.wasrised,Is.False);
};
}
公共静态操作IsPropertyChanged(对象发送方,字符串名称){
返回(EventHandlerCapture测试)=>{
NUnit.Framework.Assert.That(test.wasrised,Is.True);
NUnit.Framework.Assert.That(test.Sender,Is.SameAs(Sender));
That(test.EventArgs.PropertyName,Is.EqualTo(name));
};
}
}

如果您知道事件将同步触发:

bool eventRaised = false;
Customer customer = new Customer() { Name = "Carl" };
customer.NameChanged += (sender, e) => { eventRaised = true; };

customer.Name = "Sam";

Assert.IsTrue(eventRaised);
ManualResetEvent eventRaised = new ManualResetEvent(false);
Customer customer = new Customer() { Name = "Carl" };
customer.NameChanged += (sender, e) => { eventRaised.Set(); };

customer.Name = "Sam";

Assert.IsTrue(eventRaised.WaitOne(TIMEOUT));

如果事件可以异步触发:

bool eventRaised = false;
Customer customer = new Customer() { Name = "Carl" };
customer.NameChanged += (sender, e) => { eventRaised = true; };

customer.Name = "Sam";

Assert.IsTrue(eventRaised);
ManualResetEvent eventRaised = new ManualResetEvent(false);
Customer customer = new Customer() { Name = "Carl" };
customer.NameChanged += (sender, e) => { eventRaised.Set(); };

customer.Name = "Sam";

Assert.IsTrue(eventRaised.WaitOne(TIMEOUT));

但是,有人说应该避免测试异步行为。

我更喜欢这样做:

var wait = new AutoResetEvent(false);
foo.MeEvent += (sender, eventArgs) => { wait.Set(); };
Assert.IsTrue(wait.WaitOne(TimeSpan.FromSeconds(5)));

优点:支持多线程场景(如果在不同的线程中调用处理程序)

使用NUnit和Moq,您可以进行更健壮的事件测试

用于监视事件触发器的模拟类:

public class AssertEvent { public virtual void Call(string obj) { } }
Mock<AssertEvent> EventMock;
AssertEvent Evt;

我会将FluentAssertions与Nunit一起使用:它工作得非常好。下面是文档中的一个示例

var subject = new EditCustomerViewModel();
using (var monitoredSubject = subject.Monitor())
{
    subject.Foo();
    monitoredSubject.Should().Raise("NameChangedEvent");
}

抢手货我会更新我的答案,但没有多大意义,因为它实际上是Dror答案的重复。无论如何,我正在采取类似的方法,但更喜欢
ManualResetEvent
。这是非常古老的。。。我知道。。。我很想知道。。。是否有可能在代码到达事件部分之前调用断言?我觉得代码非常简单,这个值将在运行断言之前设置。只有当事件发生在另一个线程中时,才能在设置值之前调用断言。在这种情况下,您需要将布尔值替换为WaitHandle,并等待事件通知它。我不相信这不会获得更多的投票。这是一个很好的解决方案。FluentAssertions有一个很好的事件监视解决方案,可以很好地与Nunit配合使用。看起来很像这样