用最小起订量模拟方法并使 moq.Object 在那里可用

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

代码结构和 classes 来自这个主题:

这是我的总结。

我有以下 Interface:

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

    double CalcValueChangeAtDate(DateTime fromDate, DateTime toDate);
}

我在 class RealPosition 中实现了这样的接口:

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
    }
}

此外,我创建了另一个使用 IPosition 接口的 class:

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
        }
    }
}

我的测试设置如下所示:

[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
    }
}

问题是,在单元测试中,我所有的都是模拟职位。但是 CalcEquityCurve() 方法调用了 IPostionCalcValueChangeAtDate()。为了正确测试 CalcEquityCurve()CalcValueChangeAtDate() 必须 return 有效值。 return 值取决于方法的参数。因此,模拟对象调用 static 方法 RealPosition.CalcValueChangeAtDate().

的想法

现在我被 ??? 困住了。我根本不知道在那里写什么,以便在我调用时调用 RealPosition class 中的 static 方法:

tmpPosMoq.Object.CalcValueChangeAtDate(fromDate, toDate);

有可能吗?

感谢您的帮助! 康斯坦丁

回答你的问题,我想这就是你要问的:

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

但这完全没有意义。这只是调用实际实现的一种复杂而令人费解的方式,就像您没有模拟它一样。单元测试用于测试业务逻辑。 Mocking 用于提供虚假但真实的值,这些值通常来自无法进行实际单元测试的东西——数据库调用、Web 服务调用等。

很有可能你在这里有东西...

 // Logic here must access properties of IPosition

...是嘲笑的候选人。但是我没有看到你的构造函数中有任何依赖项,所以我什至无法猜测。