How use Moles for a constructor?
Asked Answered
M

2

7

I have a class like this:

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

I want ModifyPrice to do nothing for a specific value, but I also want to call the constructor that set the price to 10. I tried something like this:

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;

But even if fake is well-initialized with the good constructor, I can't assign it to @this. I also try something like

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

But this time I cannot call my constructor. How am I supposed to do?

Moscow answered 16/5, 2011 at 9:7 Comment(0)
J
5

You don't need to mock the constructor, the parameterless constructor of the Product class already does what you want.

Add some debugging output to 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);
    }
}

Mock only the ModifyPrice method.

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

See the debug output to confirm everything works as expected:

    Initializing price: 10
    Skipped setting price.
    New price: 210

By the way, you don't need to use the stub here,

var fake = new SProduct { CallBase = true };

creating an instance of Product will suffice.

var fake = new Product();

Update: Mocking a single method can be achieved with the AllInstances class like this

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);
Jilt answered 7/6, 2011 at 17:46 Comment(3)
Hum, you didn't understand my question. Your example have good points. However, I need a mock of Product which calls original methods, except for ModifyPrice. That why I need a CallBase = true (for a Stub) or an InstanceBehavior = MoleBehaviors.FallThrough (for a Mole). Moreover, and that's the most important point, I want to swamp all future instance of Product with my mock! That's why I need to mock the constructor.Moscow
@Moscow I may have misunderstood you again, but it looks like you could achieve what you want with the AllInstances class.Jilt
Still a good answer. I apologize for my incomplete examples, I always have other points in mind. I was comparing several mocking framework to Moles so I tried to study all possibilities. Swamp all future instance of an object with a Moles seems to be a good idea (I tried to check all methods calls and it represented to much 'AllInstances' compared to an 'NonImplementedException'). I was trying desperately to use the constructor to do '@this=aMole'... But as said in Moles manual, it's really an isolation framework and not a mock framework. Thanks for the answersMoscow
A
0
MProduct.Behavior = MoleBehaviors.Fallthrough;
Aha answered 4/8, 2011 at 13:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.