C# 如何确认在单元测试中对我的ServiceHost调用了Open()

C# 如何确认在单元测试中对我的ServiceHost调用了Open(),c#,unit-testing,mocking,rhino-mocks,servicehost,C#,Unit Testing,Mocking,Rhino Mocks,Servicehost,我有一个windows服务正在打开两个WCF服务。我想对OnStart()进行单元测试,并断言正在调用service1.Open()和service2.Open()。OnStart()如下所示: protected override void OnStart(string[] args) { // host WCF services _service1.Open(); _service2.Open(); } [TestMet

我有一个windows服务正在打开两个WCF服务。我想对OnStart()进行单元测试,并断言正在调用service1.Open()和service2.Open()。OnStart()如下所示:

protected override void OnStart(string[] args)
{
    // host WCF services            
    _service1.Open();           
    _service2.Open();
}
[TestMethod()]
public void WinServiceOnStartCallsDependenciesAsExpected()
{
    ServiceHostBase service1 = MockRepository.GenerateStub<ServiceHostBase>();
    ServiceHostBase service2 = MockRepository.GenerateStub<ServiceHostBase>();
    WinService target = new WinService(service1, service2);
    WinService_Accessor privateTarget = new WinService_Accessor(new PrivateObject(target));     
    privateTarget.OnStart(null);
我将服务注入构造函数重载中,如下所示:

public WinService(ServiceHostBase service1, 
                                  ServiceHostBase service2)
{
    _service1 = service1;
    _service2 = service2;
    InitializeComponent();
}
我使用Rhinomock生成ServiceHostBase的存根,如下所示:

protected override void OnStart(string[] args)
{
    // host WCF services            
    _service1.Open();           
    _service2.Open();
}
[TestMethod()]
public void WinServiceOnStartCallsDependenciesAsExpected()
{
    ServiceHostBase service1 = MockRepository.GenerateStub<ServiceHostBase>();
    ServiceHostBase service2 = MockRepository.GenerateStub<ServiceHostBase>();
    WinService target = new WinService(service1, service2);
    WinService_Accessor privateTarget = new WinService_Accessor(new PrivateObject(target));     
    privateTarget.OnStart(null);
[TestMethod()]
public void WinServiceOnStartCallsDependenciesAsExpected()
{
ServiceHostBase service1=MockRepository.GenerateSub();
ServiceHostBase service2=MockRepository.GenerateSub();
WinService目标=新的WinService(服务1,服务2);
WinService_访问器privateTarget=新的WinService_访问器(新的PrivateObject(target));
privateTarget.OnStart(空);
当我的测试调用OnStart()时,当它调用service1.Open()时,我会得到一个null引用异常。我已经确认service1在那一点上是一个模拟对象,并且抛出null的是Open()。我知道Open()实际上是System.ServiceModel.Channels.CommunicationObject上的一个方法,我也尝试了Stub或mock,但仍然得到了object ref错误。它不是一个虚拟方法,所以我认为它只是没有被mock版本覆盖,而是当我尝试设置expection
reportservice.Stub(r=>r.Open())时
,我得到了一个关于没有默认超时的不同异常,好像它运行的是实际的CommunicationObject Open()方法,而不是RhinoMocky抛出null ref


所有这些都是为了说明,我只是在寻找如何确认Open()的帮助正在单元测试中对我的ServiceHost进行调用。=]

ServiceHostBase。在引擎盖下打开
调用。作为其实现的一部分,它会执行许多不同的操作,例如验证对象的状态、创建其他对象、调用方法、属性等。由于它不是虚拟的(您的假设是正确的),Rhino将调用基类实现

要使其正常工作,您可能必须模拟和存根大量的
通信对象
依赖项,并且仍然无法确定您是否会成功(某些类型/方法可能只是Rhino无法修改,认为是静态的、密封的或其他非虚拟的)。这就是为什么您应该:

  • 将此类测试留给集成测试;然后将在最终用户环境中测试
    .Open
  • 引入一个大约
    ServiceHostBase
    ,并通过接口将其作为依赖项传递;这需要额外的工作(新接口和简单的包装类),但允许您完全按照自己的意愿执行

  • 请记住,添加包装器只会将问题进一步委托给包装器类“
    Open
    方法,该方法本质上将调用
    ServiceHostBase.Open
    ——您是否也应该进行单元测试?)。另一方面,集成测试可能无法像单元测试那样快速捕获问题(假设您运行它们的频率较低)取决于你认为OnOpen<代码>是多么重要,你选择哪种方式或多或少是一个判断调用。

    <代码> Service HealBase.OPEN < /Cord>在引擎盖下调用。作为其实现的一部分,它做了很多不同的事情——比如验证对象的状态、创建其他对象、调用方法、属性等。由于它不是虚拟的(您的假设是正确的),Rhino将调用基类实现

    要使其正常工作,您可能必须模拟和存根大量的
    通信对象
    依赖项,并且仍然无法确定您是否会成功(某些类型/方法可能只是Rhino无法修改,认为是静态的、密封的或其他非虚拟的)。这就是为什么您应该:

  • 将此类测试留给集成测试;然后将在最终用户环境中测试
    .Open
  • 引入一个大约
    ServiceHostBase
    ,并通过接口将其作为依赖项传递;这需要额外的工作(新接口和简单的包装类),但允许您完全按照自己的意愿执行

  • 请记住,添加包装器只会将问题进一步委托给包装器类“
    Open
    方法,该方法本质上将调用
    ServiceHostBase.Open
    ——您是否也应该进行单元测试?)。另一方面,集成测试可能无法像单元测试那样快速捕获问题(假设您运行它们的频率较低)取决于你认为《代码>OnOpen/<代码>》的重要性,你选择哪种方式或多或少是一个判断调用。

    Yea,我在讨论包装方法,但是我认为我们将不得不把它暴露出来。调用永远不会是有条件的,因此这种风险似乎不值得付出额外的复杂性。如果没有令人惊讶的事情发生,我会将此标记为答案。是的,我在讨论包装器方法,但我认为我们必须让它暴露出来。Open()呼叫永远不会是有条件的,因此,这种风险似乎不值得付出额外的复杂性。如果没有令人惊讶的事情发生,我会将此标记为答案。