C# 使用适配器模式包装系统对象(文件、ServiceController等)与单元测试绕行相比有哪些优势?

C# 使用适配器模式包装系统对象(文件、ServiceController等)与单元测试绕行相比有哪些优势?,c#,vb.net,unit-testing,mocking,C#,Vb.net,Unit Testing,Mocking,考虑以下停止服务的方法: Public Function StopService(ByVal serviceName As String, ByVal timeoutMilliseconds As Double) As Boolean Try Dim service As New ServiceController(serviceName) Dim timeout As TimeSpan = TimeSpan.FromMilliseconds(timeo

考虑以下停止服务的方法:

Public Function StopService(ByVal serviceName As String, ByVal timeoutMilliseconds As Double) As Boolean

    Try
        Dim service As New ServiceController(serviceName)
        Dim timeout As TimeSpan = TimeSpan.FromMilliseconds(timeoutMilliseconds)

        service.[Stop]()

        If timeoutMilliseconds <= 0 Then
            service.WaitForStatus(ServiceControllerStatus.Stopped)
        Else
            service.WaitForStatus(ServiceControllerStatus.Stopped, timeout)
        End If

        Return service.Status = ServiceControllerStatus.Stopped

    Catch ex As Win32Exception
        'error occured when accessing a system API'
        Return False
    Catch ex As TimeoutException
        Return False
    End Try

End Function
公共函数StopService(ByVal serviceName作为字符串,ByVal timeoutmillizes作为双精度)作为布尔值
尝试
作为新ServiceController(serviceName)的Dim服务
Dim timeout As TimeSpan=TimeSpan.FROMMISSOLES(TIMEOUTMISSOLIES)
服务。[停止]()

如果超时毫秒我认为这是一个很好的嘲弄案例,与IoC合作有一些好处:

  • 您需要进行实际的单元测试,因为您的测试不是测试底层——这将是一个集成测试

  • 易于插入和拔出模拟对象

  • 您不需要在每个存根上定义一个“假”实现。您有一个“假的”,通过配置模拟实现

对我来说,第一个原因是最重要的

你为什么不使用痣呢?因为我认为这不是适合这种情况的工具。Moles更适用于像我想要一个固定的DateTime值这样的事情。现在转到一个特定的时间,这样你就可以在任何情况下测试一些代码,而不会遇到麻烦


Moles是一种在特定测试中自动模拟某些方法和属性的简单方法,而IoC+fake则用于隔离测试。

顺便说一句,这是一个很好的问题。。刚刚看了一下摩尔女士的视频。尽管我对MS单元测试工具持怀疑态度,但我必须说这一工具看起来很有趣。我的比较是:

适配器/立面
  • Pro:允许您使用意图揭示方法提取有意义的角色。e、 g.
    ServiceManager.StartService(name)
    可以提取详细信息{1.ServiceController.GetServices(),2.handle case where ServiceController.Status!=Stopped,3.ServiceController.Start()}。这里的模拟/假方法比设置3名代表所需的工作量要少。在这里,这种方法是一个通过提出有意义的契约/接口来改进设计的机会(还允许您隐藏您不关心的内容,例如Winapi语义、常量等)
  • 赞成:模拟框架将为参数检查、调用次数、未调用期望等提供更好的诊断
拦截器
  • 赞成:如果您只想在依赖项上删除一个有问题的调用,那么就可以减少工作量
  • 赞成:在处理遗留代码(对更改的恐惧是压倒性的)时,绝对是工具箱中的一个好工具
  • 缺点:它有MSTest依赖项吗?最初的搜索似乎表明,如果您不使用MSTest,您需要一些插件或扩展

您提出了一些有效的观点,尤其是日期时间比较。然而,“可插拔性”在这种情况下并不适用,因为底层代码的更改频率是多少?除非我转移到一个非windows环境,否则在这种情况下我不认为这是一个要求。我不同意使用Moles会使测试成为一个集成测试,因为它根本不会触及底层。它将在单元测试中绕道给代表,就像在Moq中使用存根一样。我没有说“Moles会将其转换为集成测试”。这是你对我的文章的结论。我会坚持嘲笑你的想法,而不是绕道而行。如果你想抽象WinAPI,只需做IoC,并放置一个假的WinAPI包装器,然后在测试中使用它。也许我对我的想法不够清楚:)。一个简单的例子是
File.ReadAllText
和读取一个简短的示例CSV文件。在测试中,可以使用Moles来避免实际的文件系统,并将其重定向到预定义的文本数组以进行测试。在单元测试中使用代码迂回怎么会不合适呢?仅仅为了使用
ReadAllText
方法而包装File对象似乎更为不利。我的意思不是不尊重你和你辩论。我正试图更好地理解什么时候最好使用鼹鼠,什么时候不太好。你列出的国际奥委会的三大优势,我真的不相信#我不明白,马特会用痣完全避开底层#2如果Matt不需要可插拔性,那么这只是不必要的开销#3.如果你使用痣,这也是正确的。尽管我不确定单元测试对于这个例子有多大价值,不管你走哪条路。测试将证明您已经按照特定的顺序调用了特定的方法-该函数中的逻辑非常简单,您可以阅读代码。我也考虑过这一点。这种方法甚至需要测试吗。该方法(及其类)已经在使用[remote?]facade模式,因为它降低了停止服务所需的复杂性。使用服务类的代码可以在模拟服务类的情况下进行测试。因此,也许我们有一个不需要测试的代码案例,因为在某个时候,您仍然需要编写代码来访问API?然而,如何编写代码来实现与TDD相同的结果呢?这不需要对它进行测试吗?这就是这个问题的原因。@MarkJ,如果你想评论测试这个方法的有效性(从TDD的角度),我希望在这里看到你的答案:+1这很有帮助。关于鼹鼠和其他测试跑步者(如NUnit等)。是的,鼹鼠可以用这些。鼹鼠的文档说明了如何做到这一点。研究团队提供了所需的NUnit(或其他框架)扩展。