C# 使用Moq模拟事件(基于事件的异步模式)-如何对UT中的事件作出反应?

C# 使用Moq模拟事件(基于事件的异步模式)-如何对UT中的事件作出反应?,c#,unit-testing,mocking,moq,C#,Unit Testing,Mocking,Moq,我有一个通过事件驱动异步模式公开异步操作的服务 public interface IService { void DoAsync(int param); event DoCompleted; } 还有一个类依赖于IService服务对象 public class Foo { private IService _service; public EventHandler CalculationComplete; public void Foo(IService serv

我有一个通过事件驱动异步模式公开异步操作的服务

public interface IService
{
    void DoAsync(int param);
    event DoCompleted;
}
还有一个类依赖于IService服务对象

public class Foo
{
  private IService _service;
  public EventHandler CalculationComplete;
  public void Foo(IService service) {_service = service};
  public int Calculated;
  public void CalculateAsync(int param)
  {
    //Invoke _service.DoAsync(param)
    //(...)
  }
}
基本上,在调用foo.calculationEasyC CalculationComplete后,应通知消费者calc已完成


问题是在单元测试Foo时如何模拟iSeries?我正在使用最小起订量。更具体地说,如何让unittest等待CalculationComplete事件并做出相应的反应?

很难知道您在这里要测试什么,因此我无法提供100%准确的示例。您的示例代码似乎缺少很多细节。。。我填了一些遗漏的部分,但还有更多的问题

在任何情况下,我用于等待事件的方法都是信号量。我喜欢在这样简单的场合使用AutoResetEvent

public class Foo
{
  private IService _service;
  public EventHandler CalculationComplete;
  public Foo(IService service) 
  {
    _service = service;
    _service.DoCompleted += (o,e) => 
    {
            Calculated = e.Result;
        if(CalculationComplete != null) { CalculationComplete(this, new EventArgs()); }
    };
  }
  public int Calculated;
  public void CalculateAsync(int param)
  {
    _service.DoAsync(param);
  }
}


public interface IService
{
    void DoAsync(int param);
    event EventHandler<DoResultEventArgs> DoCompleted;
}

public class DoResultEventArgs : EventArgs
{
    public int Result { get; set; }
}

[TestMethod]
public void CalculateAsync_CallsService_CalculatedIsPopulated()
{
    //Arrange
    Mock<IService> sMock = new Mock<IService>();
    sMock.Setup(s => s.DoAsync(It.IsAny<int>()))
             .Raises(s => s.DoCompleted += null, new DoResultEventArgs() { Result = 324 });

    Foo foo = new Foo(sMock.Object);

    AutoResetEvent waitHandle = new AutoResetEvent(false);
    foo.CalculationComplete += (o,e) => waitHandle.Set();

    //Act
    foo.CalculateAsync(12);
    waitHandle.WaitOne();

    //Assert
    Assert.IsEqual(foo.Calculated, 324);
}
公共类Foo
{
私人电视服务;
公共事件处理程序计算完成;
公共食物(互联网服务)
{
_服务=服务;
_service.doccompleted+=(o,e)=>
{
计算=e.结果;
if(CalculationComplete!=null){CalculationComplete(this,new EventArgs());}
};
}
计算公共int;
public void CalculateAsync(int参数)
{
_服务.DoAsync(param);
}
}
公共接口设备
{
void DoAsync(int参数);
事件处理程序文档已完成;
}
公共类DoResultEventArgs:EventArgs
{
公共int结果{get;set;}
}
[测试方法]
public void CalculateAsync_calls服务_CalculatedIsPopulated()
{
//安排
模拟工作服=新模拟();
sMock.Setup(s=>s.DoAsync(It.IsAny()))
.Raises(s=>s.doccompleted+=null,新的DoResultEventArgs(){Result=324});
Foo-Foo=新的Foo(sMock.Object);
AutoResetEvent waitHandle=新的AutoResetEvent(假);
foo.CalculationComplete+=(o,e)=>waitHandle.Set();
//表演
foo.CalculateAsync(12);
waitHandle.WaitOne();
//断言
Assert.IsEqual(foo.Calculated,324);
}

没有更多的信息,这是我能做的最好的了。我希望这就是你想要的。

很难知道你在这里测试什么,所以我不能给你一个100%准确的样本。您的示例代码似乎缺少很多细节。。。我填了一些遗漏的部分,但还有更多的问题

在任何情况下,我用于等待事件的方法都是信号量。我喜欢在这样简单的场合使用AutoResetEvent

public class Foo
{
  private IService _service;
  public EventHandler CalculationComplete;
  public Foo(IService service) 
  {
    _service = service;
    _service.DoCompleted += (o,e) => 
    {
            Calculated = e.Result;
        if(CalculationComplete != null) { CalculationComplete(this, new EventArgs()); }
    };
  }
  public int Calculated;
  public void CalculateAsync(int param)
  {
    _service.DoAsync(param);
  }
}


public interface IService
{
    void DoAsync(int param);
    event EventHandler<DoResultEventArgs> DoCompleted;
}

public class DoResultEventArgs : EventArgs
{
    public int Result { get; set; }
}

[TestMethod]
public void CalculateAsync_CallsService_CalculatedIsPopulated()
{
    //Arrange
    Mock<IService> sMock = new Mock<IService>();
    sMock.Setup(s => s.DoAsync(It.IsAny<int>()))
             .Raises(s => s.DoCompleted += null, new DoResultEventArgs() { Result = 324 });

    Foo foo = new Foo(sMock.Object);

    AutoResetEvent waitHandle = new AutoResetEvent(false);
    foo.CalculationComplete += (o,e) => waitHandle.Set();

    //Act
    foo.CalculateAsync(12);
    waitHandle.WaitOne();

    //Assert
    Assert.IsEqual(foo.Calculated, 324);
}
公共类Foo
{
私人电视服务;
公共事件处理程序计算完成;
公共食物(互联网服务)
{
_服务=服务;
_service.doccompleted+=(o,e)=>
{
计算=e.结果;
if(CalculationComplete!=null){CalculationComplete(this,new EventArgs());}
};
}
计算公共int;
public void CalculateAsync(int参数)
{
_服务.DoAsync(param);
}
}
公共接口设备
{
void DoAsync(int参数);
事件处理程序文档已完成;
}
公共类DoResultEventArgs:EventArgs
{
公共int结果{get;set;}
}
[测试方法]
public void CalculateAsync_calls服务_CalculatedIsPopulated()
{
//安排
模拟工作服=新模拟();
sMock.Setup(s=>s.DoAsync(It.IsAny()))
.Raises(s=>s.doccompleted+=null,新的DoResultEventArgs(){Result=324});
Foo-Foo=新的Foo(sMock.Object);
AutoResetEvent waitHandle=新的AutoResetEvent(假);
foo.CalculationComplete+=(o,e)=>waitHandle.Set();
//表演
foo.CalculateAsync(12);
waitHandle.WaitOne();
//断言
Assert.IsEqual(foo.Calculated,324);
}
没有更多的信息,这是我能做的最好的了。我希望这就是你想要的