简体   繁体   中英

Mock a Method with Moq and make moq.Object available there

The code structure and classes emerge from this topic: C# Mock a Class With an Internal Property Setter

Here a summary of what I have.

I have the following Interface :

public interface IPosition
{
    // Some properties here which must be accessed in CalcValueChangeAtDate method.
    int Size { get; }
    ...

    double CalcValueChangeAtDate(DateTime fromDate, DateTime toDate);
}

And I implemented the interface in the class RealPosition like this:

public class RealPosition : IPosition
{
    /* IPosition implementation */
    public double CalcValueChangeAtDate(DateTime fromDate, DateTime toDate)
    {
        return CalcValueChangeAtDate(this, fromDate, toDate);
    }

    /* I created this static method with the idea to use the for mocked objects.
     * This way I would need to implement the logic only once and use it with real
     * and mocked objects*/
    public static double CalcValueChangeAtDate(IPosition pos, DateTime fromDate, DateTime toDate)
    {
        // Logic here must access properties of IPosition
    }
}

Further I created another class which uses the IPosition interface:

public class EquityCurveBuilder
{
    private static DataSeries CalcEquityCurve(List<IPosition> posDict)
    {
        DateTime fromDate;
        DateTime toDate;

        foreach (IPosition pos in posDict)
        {
            /* Here I want to call the implementation of IPosition.
             * However in my unit test posDict is a List of mocked IPositons. 
             * Simply because I don't have another choice. */
            double stockVal = pos.CalcValueChangeAtDate(fromDate, toDate);

            // Do something with stockVal
        }
    }
}

My test setup looks like this:

[Test]
public void RecalcOriginalEquityCurve()
{
    // Here I get a list of mocked IPositions
    List<IPosition> Positions   = ImporterTools.GetPositions(FilePath, FullPositionsCsv);

    // Execute Test
    DataSeries equityCurve      = EquityCurveBuilder.BuildEquityCurve(Positions);

    // Evaluate test results
    ...
}

public class ImporterTools
{
    public static List<IPosition> GetPositions(string path, string fileName)
    {
        // Import raw data and create a mocked IPosition
        Mock<IPosition> tmpPosMoq = new Mock<IPosition>();
        tmpPosMoq.Setup(v => v.CalcValueChangeAtDate(It.IsAny<DateTime>(), It.IsAny<DateTime>())).
                                                                            Returns( ??? );

        // Create a List and return it
    }
}

The problem is, that in the unit test all I have are mocked positions. But the CalcEquityCurve() method invokes CalcValueChangeAtDate() of IPostion . In order to test CalcEquityCurve() properly, CalcValueChangeAtDate() must return valid values. The return value depends on the arguments of the method. Hence the idea that the mocked object invokes the static method RealPosition.CalcValueChangeAtDate() .

Now I am stuck with the ??? . I simply don't have any idea what to write there so that my static method from the RealPosition class gets called when I call:

tmpPosMoq.Object.CalcValueChangeAtDate(fromDate, toDate);

Is it possible at all?

Thank you for your help! Konstantin

To answer your question, I think this is what you are asking for:

tmpPosMoq.Setup(v => v.CalcValueChangeAtDate(It.IsAny<DateTime>(), It.IsAny<DateTime>())).
                Returns( (DateTime dtfrom, DateTime dtto) => 
                {
                    return RealPosition.CalcValueChangeAtDate(tmpPosMoq.Object, dtfrom, dtto);
                });

But this is completely pointless. It is just a complex and convoluted way to call actual implementation that would be the exact same as if you did not mock it. Units tests are for testing business logic. Mocking is for providing fake but realistic values that would normally come from something that cannot be practically unit tested - database calls, web service calls, etc.

It is much more likely that something you have in here...

 // Logic here must access properties of IPosition

... is a candidate for mocking. But I do not see any dependencies being taken in your constructor so I can't even guess.

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