Renato Pereira
Renato Pereira

Reputation: 864

Is it possible to get mock instance from a instance using Moq?

suppose I have this interface and this class:

public interface IScheduler
{
    void StopTimer();

    // some other methods
}

public class Scheduler : IScheduler
{
    private static readonly IScheduler scheduler = new Scheduler();

    private readonly Timer timer;

    public Scheduler()
    {
        refreshTimer = new Timer
        {
            Enabled = false,
            AutoReset = false
        };
    }

    public static IScheduler GetScheduler()
    {
        return scheduler;
    }

    public void StopTimer()
    {
        timer.Stop();
    }

    // some other methods
}

So I was wondering if I could get a mock instance from the GetScheduler method. I tried something like this:

[TestMethod]
public void Execute_ButtonClicked_StopTimer()
{
    // arrange
    var mockScheduler = Mock.Get(Scheduler.GetScheduler());
    var command = GetCommandInstance();

    // act
    command.Execute();

    // assert
    mockScheduler.Verify(m => m.StopTimer());
}

but didn't work, it says "System.ArgumentException: Object instance was not created by Moq."

Any advice, please?

inside the command class there is something like this:

public void Execute()
{
    // some code
    Scheduler.GetScheduler().StopTimer();
}

Upvotes: 6

Views: 8785

Answers (3)

Stand__Sure
Stand__Sure

Reputation: 278

It's unclear what you are trying to test via the Mock.

If the test needs to check the private static field, then utilizing reflection would be the way to go, but will ultimately give the same result as Scheduler.GetScheduler().

The basic approach to get a private static field from a type is:

var field = typeof(MyType).GetField( "MethodName", BindingFlags.NonPublic | BindingFlags.Static);
var fieldValue = field.GetValue(myTypeInstance);

Mocks work against virtual address tables (at runtime, the MSIL checks the VAT for the address of the method to run). Abstract base and virtual instance methods are mockable, as are interfaces.

If virtual is added to the signature for StopTimer in the instance, it will be Mockable, which is all one would get from Mock<IScheduler>.

Upvotes: 0

Richardissimo
Richardissimo

Reputation: 5763

I propose a different approach which avoids the need to do so...

The Scheduler class is implementing the singleton pattern to control its construction. You need to be able to abstract the things which depend upon an IScheduler away from the way it is constructed. So something else should have the responsibility of managing the construction of the scheduler: it shouldn't do that itself because construction is not that class's responsibility (single responsibility principle).

Common approaches to this are to use the Gang-of-Four Factory method pattern, or a service locator pattern (e.g. Microsoft's UnityContainer). Either of these can be directed to expose that class as a singleton, leaving the class as just an implementation of what the class is responsible for.

Dependency Injection completes the jigsaw because when classes have their dependencies injected, then they themselves are abstracted away from the construction of the things which they use. So a class which needs a IScheduler would have one injected and use that.

With these patterns in place, the need to do what's being requested in the question vanishes, and leads to code with clear separation of concerns.

Footnote: I know these pattern things can look daunting, and it can seem that it's adding a lot of effort to do this, and it can be hard to see the benefit; but trust me: try this (and I really mean try it, you can't just have a half-hearted attempt, because it is quite a step change in approach). I used to write code just like you've posted. I was advised to look at these patterns. I had severe doubts, but I have never looked back, and now I write all my code this way.

Upvotes: 6

P. Roe
P. Roe

Reputation: 2117

If you wrap the call that you're trying to replace in a call that is virtual you can do it this way:

public class Scheduler : IScheduler
{
    private static readonly IScheduler scheduler = CreateScheduler();

    private readonly Timer timer;

    public Scheduler()
    {
        refreshTimer = new Timer
        {
            Enabled = false,
            AutoReset = false
        };
    }

    public static IScheduler GetScheduler()
    {
        return scheduler;
    }

    public void StopTimer()
    {
        timer.Stop();
    }

    public virtual IScheduler CreateScheduler()
    {
         return new Scheduler();
    }
    // some other methods
}

Then in your unit test class:

[TestClass]
public class TestClass
{
    [TestMethod]
    public void testMethod()
    {
        var scheduler = new Mock<Scheduler>();
        // you can now call .setup on the scheduler instance and use this mock.
        var sut = new SchedulerWrapper(scheduler.Object);

        ///var sut....sometests
    }
}

internal class SchedulerWrapper : Scheduler
{
    private Scheduler _scheduler;
    public SchedulerWrapper(Scheduler scheduler)
    {
         _scheduler;
    }
    public overrride IScheduler CreateScheduler()
    {
         return _scheduler;
    }
}

Upvotes: 0

Related Questions