【问题标题】:How use Moles for a constructor?如何将 Moles 用于构造函数?
【发布时间】:2011-08-26 06:56:30
【问题描述】:

我有这样的课:

public class Product : IProduct
{
    static private string _defaultName = "default";
    private string _name;
    private float _price;
    /// Constructor
    public Product()
    {
        _price = 10.0F;
    }
    public void ModifyPrice(float modifier)
    {
        _price = _price * modifier;
    }  

我希望 ModifyPrice 对特定值不执行任何操作,但我也想调用将价格设置为 10 的构造函数。我尝试过这样的操作:

var fake = new SProduct() { CallBase = true };
var mole = new MProduct(fake)
    {
        ModifyPriceSingle = (actual) =>
        {
            if (actual != 20.0f)
            {
                MolesContext.ExecuteWithoutMoles(() => fake.ModifyPrice(actual));
            }
        }
    };
MProduct.Constructor = (@this) => (@this) = fake;

但即使 fake 用好的构造函数很好地初始化,我也不能将它分配给@this。我也尝试类似

MProduct.Constructor = (@this) => { var mole = new MProduct(@this)... };

但这一次我不能调用我的构造函数。我该怎么办?

【问题讨论】:

    标签: c# .net unit-testing mocking moles


    【解决方案1】:

    你不需要mock构造函数,Product类的无参数构造函数已经做了你想要的。

    添加一些调试输出到Product

    public class Product
    {
        private float _price;
        public Product()
        {
            _price = 10.0F;
            Debug.WriteLine("Initializing price: {0}", _price);
        }
        public void ModifyPrice(float modifier)
        {
            _price = _price*modifier;
            Debug.WriteLine("New price: {0}", _price);
        }
    }
    

    仅模拟 ModifyPrice 方法。

    [TestMethod]
    [HostType("Moles")]
    public void Test1()
    {
        // Call a constructor that sets the price to 10.
        var fake = new SProduct { CallBase = true };
        var mole = new MProduct(fake)
        {
            ModifyPriceSingle = actual =>
            {
                if (actual != 20.0f)
                {
                    MolesContext.ExecuteWithoutMoles(() => fake.ModifyPrice(actual));
                }
                else
                {
                    Debug.WriteLine("Skipped setting price.");
                }
            }
        };
        fake.ModifyPrice(20f);
        fake.ModifyPrice(21f);
    }
    

    查看调试输出以确认一切正常:

    初始化价格:10 跳过设定价格。 新价格:210

    顺便说一句,这里不需要使用存根,

    var fake = new SProduct { CallBase = true };
    

    创建Product 的实例就足够了。

    var fake = new Product();
    

    更新: 像这样使用AllInstances 类可以实现模拟单个方法

    MProduct.Behavior = MoleBehaviors.Fallthrough;
    MProduct.AllInstances.ModifyPriceSingle = (p, actual) =>
    {
        if (actual != 20.0f)
        {
            MolesContext.ExecuteWithoutMoles(() => p.ModifyPrice(actual));
        }
        else
        {
            Debug.WriteLine("Skipped setting price.");
        }
    };
    
    // Call the constructor that sets the price to 10.
    Product p1 = new Product();
    // Skip setting the price.
    p1.ModifyPrice(20f);
    // Set the price.
    p1.ModifyPrice(21f);
    

    【讨论】:

    • 哼,你没听懂我的问题。你的例子有好处。但是,我需要一个调用原始方法的 Product 模拟,ModifyPrice 除外。这就是为什么我需要 CallBase = true(对于 Stub)或 InstanceBehavior = MoleBehaviors.FallThrough(对于 Mole)。此外,这是最重要的一点,我想用我的模拟淹没所有未来的 Product 实例!这就是为什么我需要模拟构造函数。
    • @Jeco 我可能又误解了你,但看起来你可以通过AllInstances 类实现你想要的。
    • 仍然是一个很好的答案。我为我不完整的例子道歉,我总是有其他的想法。我正在将几个模拟框架与 Moles 进行比较,因此我尝试研究所有可能性。用 Moles 淹没对象的所有未来实例似乎是一个好主意(我试图检查所有方法调用,与“NonImplementedException”相比,它代表了很多“AllInstances”)。我拼命地尝试使用构造函数来执行“@this=aMole”......但正如 Moles 手册中所说,它实际上是一个隔离框架而不是模拟框架。感谢您的回答
    【解决方案2】:
    MProduct.Behavior = MoleBehaviors.Fallthrough;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-09-21
      • 2023-04-05
      • 2018-03-27
      • 2020-03-12
      • 2012-12-05
      • 1970-01-01
      相关资源
      最近更新 更多