简体   繁体   中英

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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM