blgrnboy
blgrnboy

Reputation: 5167

Moq - Can't mock a class property's method return value

How can I mock the CasOperations.GetImpairedNodesFromCASpectrumAsync() method so that it returns the mocked value? Currently, I am getting an exception (shown below the code examples).

I have the following setup:

Class and property to be mocked:

public class BranchCircuitStatusScheduleEntry : NWatchCustomScheduleEntryBase, INWatchCustomScheduleEntry
{
    public BranchCircuitStatusScheduleEntry(INWatchSchedulerApplication application)
        : base(application, DevOpsScheduleFrequency.Minute, 15, 0, DevOpsScheduleFlags.Always)
    {
        // Some initialization for below properties
        CasOperations = new CasOperations(cas, EntityService, IsBranchesOnly);
    }

    public CasOperations CasOperations { get; private set; }

}

public class CasOperations
{
    public CasOperations(CasApi casApi, BranchCircuitEntityService entityService, bool isBranchesOnly)
    {
        CAS = casApi;
        this.entityService = entityService;
        this.isBranchesOnly = isBranchesOnly;
    }
}

Test that tries to perform mocking:

[TestMethod]
public void DownNodeRediscoveredInSpectrum()
{
    var mock = new Mock<BranchCircuitStatusScheduleEntry>(_application);
    mock.CallBase = true;

    // Spectrum's artificial response with a model with the same name, but a "new" model handle
    var mockedNewlyImpairedNodes = new NetworkDeviceNodeStatus[]
    {
        new NetworkDeviceNodeStatus
        {
            // Not important
        }
    };

    mock.Setup(x =>
        x.CasOperations.GetImpairedNodesFromCASpectrumAsync()).ReturnsAsync(mockedNewlyImpairedNodes);
}

Exception thrown in the test:

An exception of type 'Castle.DynamicProxy.InvalidProxyConstructorArgumentsException' occurred in Moq.dll but was not handled in user code Additional information: Can not instantiate proxy of class: NWatch.NetworkCircuits.CasOperations. Could not find a parameterless constructor.

Upvotes: 3

Views: 5647

Answers (1)

Charlie
Charlie

Reputation: 664

Allow me to give it a try:

In the setup of the mock you are not trying to mock the behaviour of the BranchCircuitStatusScheduleEntry, but the behaviour of the CasOperations class. So you really need a Mock<CasOperations> object. Or even better, a Mock<ICasOperations> as @Jonesopolis said in his comment.

Besides, in the BranchCircuitStatusScheduleEntry constructor you are initializing both the instance of that class and the instance of CasOperations. It would be better if you initialize the instance of CasOperations outside the BranchCircuitStatusScheduleEntry constructor and pass it as a parameter.

So it would be like this:

public class BranchCircuitStatusScheduleEntry : NWatchCustomScheduleEntryBase, INWatchCustomScheduleEntry
{
    public BranchCircuitStatusScheduleEntry(INWatchSchedulerApplication application, ICasOperations casOperations)
        : base(application, DevOpsScheduleFrequency.Minute, 15, 0, DevOpsScheduleFlags.Always)
    {
        CasOperations = casoperations;
    }

    public CasOperations CasOperations { get; private set; }
}

Finally, you create your mock, set it up and pass it as a parameter to the BranchCircuitStatusScheduleEntry constructor:

var casMock = new Mock<ICasOperations>();
casMock.Setup(x => x.GetImpairedNodesFromCASpectrumAsync()).ReturnsAsync(mockedNewlyImpairedNodes);

var mock = new Mock<BranchCircuitStatusScheduleEntry>(_application, casMock.Object);
mock.CallBase = true;

Note that maybe this last instance of BranchCircuitStatusScheduleEntry should not be a mock, but a real object (the instance under test).

Upvotes: 5

Related Questions