c# - 如何使用 xUnit 对 C# 事件进行单元测试

标签 c# .net events xunit xunit.net

我想对由被测类订阅的依赖项引发的事件进行单元测试。
为了设置上下文,我有以下接口(interface)和类。

ITestedService.cs

public interface ITestedService
{
  Task Start();
  Task Stop();
}


IDependency.cs

public interface IDependency
{
    event EventHandler<SoAndSoEventArgs> SomethingHappened;
    Task Start();
    Task Stop();
}

ISecondDependency

public interface ISecondDependency
{
    Task DoYourJob(SoAndSo soAndSo);
}

测试服务.cs

public class TestedService : ITestedService
{
    readonly IDependency m_dependency;
    readonly ISecondDependency m_secondDependency;

    public TestedService(
        IDependency dependency,
        ISecondDependency secondDependency)
    {
        m_dependency = dependency;
        m_secondDependency = secondDependency;
    }

    public async Task Start()
    {
        m_dependency.SomethingHappened +=  OnSomethingHanppened;
        await m_dependency.Start();
    }

    private async void OnSomethingHanppened(object sender, SoAndSoEventArgs args)
    {
        SoAndSo soAndSo = SoAndSoMapper.MapToDTO(args);
        await m_secondDependency.DoYourJob(soAndSo),
    }

}


有了上面的上下文,我想对 Start() 进行单元测试TestedService 的方法使用 xUnit 的类.
我想知道我该怎么做:
  • 断言事件是否附加到处理程序。
  • 模拟事件IDependency.SomethingHappened被解雇。
  • 验证 OnSomethingHappened方法执行
  • 验证 ISecondDependency.DoYourJob(soAndSo)叫做。
  • 最佳答案

    来自 this answer , this documentation根据@ZevSpitz 在评论中的指导,我能够为 Start() 编写以下测试。
    虽然我无法验证相同的代码路径 OnSomethingHappened被执行或者是其他一些调用 m_secondDependencyMock.DoYourJob(soAndSo) 的订阅.

    TestedServiceTest.cs

    public class TestedServiceTest
    {
        readonly Mock<IDependency> m_dependencyMock;
        readonly Mock<ISecondDependency> m_secondDependencyMock;
    
        ITestedService testedService;
    
        public TestedServiceTest()
        {
            m_dependencyMock = new Mock<IDependency>();
            m_secondDependencyMock = new Mock<ISecondDependency>();
            testedService = new TestedService(m_dependencyMock.Object, m_secondDependencyMock.Object);
        }
    
        [Fact]
        public async Start_DependencyStartInvoked()
        {
            // Arrange
            m_dependencyMock.Setup(x=> x.Start()).Verifyable();
    
            // Act 
            await testedService.Start();
    
            // Assert
            //This tests if the IDependecy.Start is invoked once.
            m_dependencyMock.Verify(x=>x.Start(), Times.Once);
        }
    
        [Fact]
        public async Start_EventListenerAttached()
        {
            // Arrange
            m_dependencyMock.Setup(x=> x.Start()).Verifyable();
            m_dependencyMock.SetupAdd(m => m.SomethingHappened += (sender, args) => { });
    
            // Act 
            await testedService.Start();
    
            // Assert
            // The below together with SetupAdd above asserts if the TestedService.Start adds a new eventlistener
            // for IDependency.SomethingHappened
            m_dependencyMock.VerifyAdd(
                m => m.SomethingHappened += It.IsAny<EventHandler<SoAndSoEventArgs>>(), 
                Times.Exactly(1));
        }
    
        [Fact]
        public async Start_SomthingHappenedInvoked_HandlerExecuted()
        {
            // Arrange
            m_dependencyMock.Setup(x=> x.Start()).Verifyable();
            m_secondDependencyMock.Setup(x=> x.DoYourJob(It.IsAny<SoAndSo>())).Verifyable();
    
            // Act
            await testedService.Start();
            // This will fire the event SomethingHappened from m_dependencyMock.
            m_dependencyMock.Raise(m => m.SomethingHappened += null, new SoAndSoEventArgs());
    
            // Assert
            // Assertion to check if the handler does its job.
            m_secondDependencyMock.Verify(x=> x.DoYourJob(It.IsAny<SoAndSo>()), Times.Once);
        }
    }
    
    

    关于c# - 如何使用 xUnit 对 C# 事件进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59312203/

    相关文章:

    c# - 为什么内部 .NET 方法比从 .NET 开源复制的简单代码快得多?

    c# - 在我的项目中仅针对 Owned<T> 引用 Autofac 是不是糟糕的设计?

    .net - Thread.SpinWait 方法的目的是什么?

    .net - 有选择地禁用 .NET Framework 的版本

    带有多个参数的 AngularJS $broadcast

    java - 拦截 JavaScript 卸载事件

    c++ - 如何将 QEvents 传递给子部件?

    c# - 无法从我的程序写入另一台计算机中的 XML 文件

    c# - 如何更改 TagHelpers 中 ModelExpression 的类类型?

    c# - C# 中有哪些良好的编程实践可以使代码更加不言自明?