17

I have number of classes I've been asked to add some unit tests to with Rhino Mocks and having some issues.

First off, I know RhinoMocks doesn't allow for the mocking of Static members. I'm looking for what options I have (besides using TypeMock).

An example of the class I have is similar to the below:

class Example1 : ISomeInterface
{
    private static ISomeInterface _instance;

    private Example1()
    {
        // set properties via private static methods
    }

    static Example1()
    {
        _instance = new Example1();
    }

    public static ISomeInterface Instance() 
    {
        get { return _instance; }
    }

    // Instance properties 

    // Other Instance Properties that represent objects that follow a similar pattern.
}

So when I call the above class, it looks something like this...

Example1.Instance.SomeObject.GoDownARabbitHole();

Is there a way for me to mock out the SomeObject.GoDownARabbitHole() in this situation or mock out the Instance?

JamesEggers
  • 12,885
  • 14
  • 59
  • 86
  • Have you tried Moq instead of Rhino? I believe it will allow you to mock static methods. See http://www.superexpert.com/blog/archive/2008/06/12/tdd-introduction-to-moq.aspx and the section with adaptor pattern to mock a static method – Lucas B Jan 12 '10 at 17:36
  • Sadly, the decision to change the mocking framework is out of my hands. I'm in a huge code base and it's standardized on Rhino. As for using the adapter pattern to mock a static method, the same can be done using Rhino as well. The issue I'm having is more with the singleton being create via a static method than the testing of a static method itself. – JamesEggers Jan 12 '10 at 17:48
  • Moq cannot mock static methods, without following the adapter pattern. I should add as a side note, it's much nicer than Rhino and other mocking frameworks. – Finglas Jan 12 '10 at 17:54

7 Answers7

29

Discouraged by threads like this, it took me quite some time to notice, that singletons are not that hard to mock. After all why are we using c#?

Just use Reflection.

With provided sample code you need to make sure the static constructor is called before setting the static field to the mocked object. Otherwise it might overwrite your mocked object. Just call anything on the singleton that has no effect before setting up the test.

ISomeInterface unused = Singleton.Instance();

System.Reflection.FieldInfo instance = typeof(Example1).GetField("_instance", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);

Mock<ISomeInterface> mockSingleton = new Mock<ISomeInterface>();
instance.SetValue(null, mockSingleton.Object);

I provided code for mocking with Moq, but I guess Rhino Mocks is quite similar.

No answer
  • 907
  • 1
  • 9
  • 10
  • just used this at work and got someone back on the rails. thanks so much. – JJS Oct 16 '13 at 20:55
  • 3
    The problem is that most singletons ain't based on interfaces. It's quite rare I would say. If one has an interface then one should know better not to use Singletons but rather Dependency Injection. – andrew.fox Mar 09 '15 at 10:00
  • 1
    wow, this solution make it worth to refactor my singletons to implement interfaces. – silver Jul 20 '15 at 14:35
  • 2
    One item to add. Once it has been mocked, your other tests will also being using the mock. You may not want that. At the end of the test you should remove the mock using: instance.SetValue("_instance", null); – Roger Sep 25 '18 at 16:44
14

Singletons are at odds with Testability because they are so hard to change. You would be much better off using Dependency Injection to inject an ISomeInterface instance into your consuming classes:

public class MyClass
{
    private readonly ISomeInterface dependency;

    public MyClass(ISomeInterface dependency)
    {
        if(dependency == null)
        {
            throw new ArgumentNullException("dependency");
        }

        this.dependency = dependency;
    }

    // use this.dependency in other members
}

Notice how the Guard Claus together with the readonly keyword guarantees that the ISomeInterface instance will always be available.

This will allow you to use Rhino Mocks or another dynamic mock library to inject Test Doubles of ISomeInterface into the consuming classes.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Dependency Injection can significantly increase code complexity sometimes. Imagine you have an ambient dependency, that should be accessed easily from all places in your code. `static` instance is the better choice because otherwise you just pollute all your constructors. – Konrad Dec 14 '18 at 18:50
  • One of such dependencies is localizer that should translate your strings. It will obviously access some file or database to load the translations and you have to mock it. It's not impossible to mock static instances. And injecting localizer in every class is just ugliness ! – Konrad Dec 14 '18 at 18:51
  • https://stackoverflow.com/questions/46801776/mock-static-class-using-moq-in-c-sharp?rq=1 – Konrad Dec 14 '18 at 19:02
  • It's not always possible to refactor an existing singleton to DI – bus1hero Aug 25 '22 at 13:18
  • @bus1hero Why not? – Mark Seemann Aug 25 '22 at 13:33
  • @MarkSeemann When you have an existing application that heavily relies on singletons and it's a critical piece of your business, you cannot just go and refactor everything to use DI! The cost of error is too high, so it's to risky! Probably, it wasn't the wisest idea to use singletons but here we are. – bus1hero Aug 26 '22 at 06:54
  • @bus1hero Yes, there are always practical considerations, and you may decide that it's not worth the effort. That is not the same as it being impossible, or even that hard. Refactoring gradually is less risky that trying to make a single big change. – Mark Seemann Aug 26 '22 at 07:00
6

Here's a low-touch approach that uses a delegate, which can be set initially and changed at runtime. It's better explained by example (specifically, mocking DateTime.Now):

http://www.lostechies.com/blogs/jimmy_bogard/archive/2008/11/09/systemtime-versus-isystemclock-dependencies-revisited.aspx

Peter Seale
  • 4,835
  • 4
  • 37
  • 45
5

Example from Book: Working Effectively with Legacy Code

To run code containing singletons in a test harness, we have to relax the singleton property. Here’s how we do it. The first step is to add a new static method to the singleton class. The method allows us to replace the static instance in the singleton. We’ll call it setTestingInstance.

public class PermitRepository
{
    private static PermitRepository instance = null;
    private PermitRepository() {}
    public static void setTestingInstance(PermitRepository newInstance)
    {
        instance = newInstance;
    }
    public static PermitRepository getInstance()
    {
        if (instance == null) 
        {
            instance = new PermitRepository();
        }
        return instance;
    }
    public Permit findAssociatedPermit(PermitNotice notice) 
    {
    ...
    }
...
}

Now that we have that setter, we can create a testing instance of a PermitRepository and set it. We’d like to write code like this in our test setup:

public void setUp() {
PermitRepository repository = new PermitRepository();
...
// add permits to the repository here
...
PermitRepository.setTestingInstance(repository);
}
Stealth Rabbi
  • 10,156
  • 22
  • 100
  • 176
Teoman shipahi
  • 47,454
  • 15
  • 134
  • 158
  • Man, I like your suggestion for two reasons: simple and realistic. I am studying it today because I'm starting to have problems with singletons when implementing tests. I implemented a similar solution to the one you put even without having read the book (it's on my list of "to read"). I was feeling uncomfortable because most of the answers and articles that I found gave answers that are simplistic at best (at least for an enterprise application with 60K lines of code). Now I'm more comfortable in knowing that someone respected wrote this in a book. After all, Michael Feathers suggested it. – Marlon Patrick Apr 11 '15 at 23:16
  • 1
    @Teoman shipahi: I like this idea, but how can you call `new PermitRepository()` in your test if the constructor is `private` (which is very usual for singletons)? – György Balássy Apr 03 '18 at 15:18
  • @GyörgyBalássy Edit: I believe author intended to use PermitRepository in setup is a mock class by itself. https://books.google.com/books?id=fB6s_Z6g0gIC&pg=PA121&lpg=PA121&dq=Working+Effectively+with+Legacy+Code+permit+repository&source=bl&ots=Z6LpOFFWDf&sig=Pi7WAA4RcguH9cld_rIyKtuqeXg&hl=en&sa=X&ved=0ahUKEwj0tPSgtJ7aAhWBKGMKHaVcAoEQ6AEIbDAI#v=onepage&q=Working%20Effectively%20with%20Legacy%20Code%20permit%20repository&f=false – Teoman shipahi Apr 03 '18 at 15:24
1

Check out Dependency Injection.

You've already began this, but for hard to test classes (statics etc...) you can use the adapter design pattern to write a wrapper around this hard to test code. Using the interface of this adapter, you can then test your code in isolation.

For any unit testing advice, and further testing issues check out the Google Testing Blog, specifically Misko's articles.

Instance

You say you are writing tests, so it may be too late, but could you refactor the static to the instance? Or is there a genuine reason why said class should remain a static?

Finglas
  • 15,518
  • 10
  • 56
  • 89
  • The example usage line I gave under the class definition is used in probably close to 100 or more files. I'm actually trying to test a class that calls this static singleton class which is simple if I could mock this away. So the workload to turn it into an instance class and not a static singleton would be risky sadly. – JamesEggers Jan 12 '10 at 18:16
  • That's fair enough. In that case, DI would be the way to go. Happy testing. – Finglas Jan 12 '10 at 18:37
0

You can mock the interface, ISomeInterface. Then, refactor the code that uses it to use dependency injection to get the reference to the singleton object. I have come across this problem many times in our code and I like this solution the best.

for example:

public class UseTheSingleton
{
    private ISomeInterface myX;

    public UseTheSingleton(ISomeInterface x)
    {
        myX = x;
    }

    public void SomeMethod()
    {
        myX.
    }
}

Then ...

UseTheSingleton useIt = UseTheSingleton(Example1.Instance);
TheSean
  • 4,516
  • 7
  • 40
  • 50
0

You don't have to fix all the uses at once, just the one you're dealing with now. Add an ISomeInterface field to the class under test and set it through the constructor. If you're using Resharper (you are using Resharper, aren't you?), most of this will be trivial to do. If this is really fiddly, you can have more than one constructor, one which sets the new dependency field, the other which calls the first one with the singleton as a default value.

Steve Freeman
  • 2,707
  • 19
  • 14