Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the advantages to wrapping system objects (File, ServiceController, etc) using the Adapter pattern vs. detouring for unit testing?

Consider the following method that stops a service:

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

In order to unit test the the method I basically have two options:

  1. Use the Adapter pattern to wrap the ServiceController class's methods I need into an interface I can control. This interface can then be injected into the service class (a.k.a Inversion of Control). This way I have a loosely coupled code and can use the traditional mocking frameworks to test.
  2. Keep the class as is and use Microsoft Moles (or any other code detouring framework) to intercept the calls to ServiceController to return canned results for testing purposes.

I agree that for domain model code that using the "traditional" unit testing approach makes the most sense as this would lead to a design that is easiest to maintain. However, for code that deals with the .net implementation of Windows API related stuff (file system, services, etc), is there really an advantage to going thru the extra work to get "traditionally" testable code?

It's hard for me to see the disadvantages of using Microsoft Moles for things such as ServiceController (or the File object). I really don't see any advantage of doing the traditional approach in this case. Am I missing anything?

like image 965
Matt Avatar asked Feb 09 '11 14:02

Matt


People also ask

Why do we need unit tests?

Unit testing ensures that all code meets quality standards before it's deployed. This ensures a reliable engineering environment where quality is paramount. Over the course of the product development life cycle, unit testing saves time and money, and helps developers write better code, more efficiently.

Are unit tests worth it?

Unit tests are a way to ensure your code still works after you make changes. They can be a challenge to get right, but they're worth the effort. By writing unit tests, you can ensure your code still works as expected and prevent regressions. Most developers agree that unit testing is a good practice, but few do it.

How do you do unit testing?

A typical unit test contains 3 phases: First, it initializes a small piece of an application it wants to test (also known as the system under test, or SUT), then it applies some stimulus to the system under test (usually by calling a method on it), and finally, it observes the resulting behavior.


2 Answers

Great question btw.. Just had a look at MS Moles video right now. Although I'm skeptical of MS Unit-testing tools, I must say this one looks interesting. My comparison stands at:

Adapter/Facade

  • Pro: allows you to extract a meaningful role with intention revealing methods. e.g. ServiceManager.StartService(name) could abstract the details {1. ServiceController.GetServices(), 2. handle case where ServiceController.Status != Stopped, 3. ServiceController.Start()}. The mock/fake approach here would involve less work than setting up 3 delegates. Here this approach is an opportunity to improve your design by coming up with meaningful contracts/interfaces (also allows you to hide stuff that you don't care about -- e.g. Winapi semantics, constants, etc)
  • Pro: Mocking frameworks would give you better diagnostics for argument checks, number of times called, expectations not called etc.

Interceptor

  • Pro: Less work if you're just interested in stubbing out a problematic call on a dependency
  • Pro: definitely a good tool in your toolbox when dealing with legacy code (where the fear of change is overwhelming)
  • Con: does it have a MSTest dependency? Initial searches seem to indicate that you need some plugins or extensions if you're not using MSTest.
like image 80
Gishu Avatar answered Nov 14 '22 22:11

Gishu


I believe that this is a good case for mocking and there're some advantages of doing it with IoC:

  • You do actual unit-testing, as your tests aren't testing underlying layers - this would be an integration test -.

  • Easy to plug and unplug a mock object.

  • You don't need to define a "fake" implementation on each stub. You've a "fake", mocked implementation by configuration.

For me, the first reason is the most important.

Why don't to use Moles? Because I believe it's not the right tool for something like this. Moles is more for things like I want a fixed value of DateTime.Now to an specific time, so you can test some code in some situation whenever you want with no troubles.

Moles is an easy way to auto-mock certain methods, properties in specific tests, while IoC+fake, it's to isolate your test.

like image 26
Matías Fidemraizer Avatar answered Nov 14 '22 23:11

Matías Fidemraizer