代码之家  ›  专栏  ›  技术社区  ›  atamanroman

与Nunit的测试活动

  •  34
  • atamanroman  · 技术社区  · 15 年前

    我刚从TDD开始,可以独自解决我面临的大部分问题。但现在我迷路了:我怎么能检查事件是否被解雇?我在找类似的东西 Assert.Raise Assert.Fire 但什么都没有。谷歌不是很有用,大部分的点击量都是建议,比如 foo.myEvent += new EventHandler(bar); Assert.NotNull(foo.myEvent); 但这证明不了什么。

    谢谢您!

    8 回复  |  直到 8 年前
        1
  •  45
  •   AlG    9 年前

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

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

    根据要求-不含羔羊:

    var wasCalled = false;
    foo.NyEvent += delegate(o,e){ wasCalled = true;}
    
    ...
    
    Assert.IsTrue(wasCalled);
    
        2
  •  11
  •   aderesh    10 年前

    我喜欢这样做:

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

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

        3
  •  9
  •   Clay hemu    12 年前

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

    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));
    

    然而,一些人认为应该避免测试异步行为。

        4
  •  5
  •   earlNameless    13 年前

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

    下面是 ClassUnderTest 具有 NameChanged 测试的事件 MyTests 测验:

    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);
        }
    }
    

    支持类如下。这些类可以与任何 EventHandler<TEventArgs> 或者扩大到其他代表。事件测试可以嵌套。

    /// <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));
            };
        }
    }
    
        5
  •  1
  •   theburningmonk    15 年前

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

    类似:

    bool eventFired = false;
    foo.MyEvent += (s, e) => { eventFired = true };
    
    Assert.IsTrue(eventFired);
    
        6
  •  1
  •   Manfred    15 年前

    @烧僧:一个“;”不见了。修正版本为:

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

    干杯!;-)

        7
  •  1
  •   Greg    8 年前

    使用nunit和moq,您可以进行更健壮的事件测试。

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

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

    事件触发器的设置:

    [SetUp]
    public void TestInit() {
        EventMock = new Mock<AssertEvent>();
        Evt= EventMock.Object;
    }
    

    在测试中使用模拟对象:

    [Test]
    public void TestMethod() {
        myObject.Event1 += (sender, args) => Evt.Call("Event1Label");
        myObject.Event2 += (sender, args) => Evt.Call("Event2Label");
        myObject.Event3 += (sender, args) => Evt.Call("Event3Label");        
    
        myObject.SomeEventTrigger();
    
        EventMock.Verify(m => m.Call("Event1Label"), Times.Exactly(1));
        EventMock.Verify(m => m.Call("Event2Label"), Times.Never());
        EventMock.Verify(m => m.Call("Event3Label"), Times.Between(1,3);
    
    }
    
        8
  •  0
  •   DixonD    15 年前

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