使用适配器模式包装系统对象(File,ServiceController等)与单元测试绕行有什么好处?

Mat*_*att 8 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(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
Run Code Online (Sandbox Code Playgroud)

为了对单元测试方法我基本上有两个选择:

  1. 使用Adapter模式将ServiceController我需要的类的方法包装到我可以控制的接口中.然后可以将此接口注入服务类(也称为控制反转).这样我就可以使用松散耦合的代码,并可以使用传统的模拟框架进行测试.
  2. 按原样保留类,并使用Microsoft Moles(或任何其他代码绕行框架)拦截调用ServiceController以返回预设结果以进行测试.

我同意对于使用"传统"单元测试方法的域模型代码最有意义,因为这会导致设计最容易维护.但是,对于处理与Windows API相关的东西(文件系统,服务等)的.net实现的代码,通过额外的工作获得"传统的"可测试代码是否真的有优势?

我很难看到将Microsoft Moles用于诸如ServiceController(或File对象)之类的东西的缺点.在这种情况下,我真的没有看到采用传统方法的任何优势.我错过了什么吗?

Gis*_*shu 1

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

适配器/外观

  • 优点:允许您通过意图揭示方法提取有意义的角色。例如ServiceManager.StartService(name)可以抽象细节{1。ServiceController.GetServices(), 2. 处理 ServiceController.Status != Stopped 的情况,3. ServiceController.Start()}。这里的模拟/假方法比设置 3 个代表需要更少的工作。这种方法是通过提出有意义的契约/接口来改进设计的机会(还允许您隐藏您不关心的东西 - 例如 Winapi 语义、常量等)
  • 优点:模拟框架将为您提供更好的参数检查诊断、调用次数、未调用的期望等。

拦截器

  • 优点:如果您只是想消除对依赖项的有问题的调用,则工作量会减少
  • 优点:在处理遗留代码时(对变化的恐惧是压倒性的),绝对是你工具箱中的一个好工具
  • 缺点:它有 MSTest 依赖性吗?初步搜索似乎表明,如果您不使用 MSTest,则需要一些插件或扩展。