用Moq模拟方法并在那里使moq.Object可用 [英] Mock a Method with Moq and make moq.Object available there

查看:67
本文介绍了用Moq模拟方法并在那里使moq.Object可用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此主题中出现了代码结构和类: C#模拟具有内部属性设置器的类

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

这是我所拥有的摘要.

我有以下Interface:

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

    double CalcValueChangeAtDate(DateTime fromDate, DateTime toDate);
}

我在类RealPosition中实现了接口,如下所示:

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

我还创建了另一个使用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
        }
    }
}

我的测试设置如下:

[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()必须返回有效值.返回值取决于方法的参数.因此,模拟对象调用static方法RealPosition.CalcValueChangeAtDate()的想法.

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

现在,我坚持使用???.我根本不知道在那写什么,所以我在调用时调用RealPosition类的static方法:

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

有可能吗?

谢谢您的帮助! 康斯坦丁

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

但这是完全没有意义的.这只是调用实际实现的一种复杂而复杂的方式,与您没有模拟它的方式完全相同.单元测试用于测试业务逻辑.模拟是为了提供虚假但现实的值,这些值通常来自无法进行单元测试的东西,例如数据库调用,Web服务调用等.

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.

这篇关于用Moq模拟方法并在那里使moq.Object可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆