This is a migrated thread and some comments may be shown as answers.

Mock objects not always being used

2 Answers 51 Views
General Discussions
This is a migrated thread and some comments may be shown as answers.
Peter
Top achievements
Rank 1
Peter asked on 08 Sep 2013, 04:26 AM
I'm trying to test the following, and the class under test's internals are visible to the test class:

public class PriceSeries
{
    private double _avPrice = 650;
    private double _relativePriceVol = 0.025;
    private double _priceRegress = 0.2;
    private double _currPrice = 650;
 
    private readonly Random _oracle = new Random();
 
    public double AvPrice
    {
        get { return _avPrice; }
        private set { if(value > 0) {_avPrice = value;} }
    }
 
    public double CurrPrice
    {
        get { return _currPrice; }
        private set { if (value > 0) { _currPrice = value; } }
    }
 
    public double RelativePriceVol
    {
        get { return _relativePriceVol; }
        private set { if(value > 0 && value < 1) { _relativePriceVol = value; } }
    }
 
    public double PriceRegress
    {
        get { return _priceRegress; }
        private set { if (value > 0 && value < 1) { _priceRegress = value; } }
    }
 
    /// <summary>
    /// Return NdX
    /// </summary>
    /// <param name="numdice">Number of dice being rolled</param>
    /// <param name="numfaces">Highest numbered face on die</param>
    /// <returns></returns>
    internal int[] RollDice(int numdice, int numfaces)
    {
        numdice = Math.Max(1, numdice);
        numfaces = Math.Max(1, numfaces);
        int[] dice = new int[numdice];
        for(int i=0;i<numdice;i++)
        { dice[i] = RollOneDie(numfaces); }
        return dice;
    }
 
    public double GetNextPrice()
    {
        int[] dice = RollDice(4, 6);
        int sum = -14;
        foreach(int t in dice)
        { sum += t; }
        double result = this.CurrPrice + this.PriceRegress*(this.AvPrice - this.CurrPrice)
 +
this.AvPrice*this.RelativePriceVol*sum;
        return result;
    }
 
    internal int RollOneDie(int numfaces)
    {
        return _oracle.Next(numfaces) + 1;
    }
}


With these unit tests

[TestMethod]
public void TestFirstPriceGen()
{
    PriceSeries target = new PriceSeries();
    // mock out dice roll
    int[] mockroll = new int[] {3,5,4,5};
    Mock.Arrange(() => target.RollDice(4, 6)).Returns(mockroll);
     
    double expectedPrice = 698.75;  // dice roll of +3 from initialisation
 
    double actualPrice = target.GetNextPrice();
    Assert.AreEqual(expectedPrice,actualPrice);
    Mock.Assert(() => RollDice(4,6),Occurs.Once());

}
 
[TestMethod]
public void TestRollDice()
{
    PriceSeries target = new PriceSeries();
    Mock.Arrange(() => RollOneDie(6)).Returns(3);
 
    int[] expectedd6 = {3};
    int[] actuald6 = target.RollDice(1, 6);
    Mock.Assert(() => RollOneDie(6), Occurs.Once());
    Assert.AreEqual(expectedd6.Length,actuald6.Length);
    Assert.AreEqual(expectedd6[0],actuald6[0]);         
}


 I'm using VS2010, JetBrains ReSharper 7.0.1, and JetBrains dotCover2.2.  

TestFirstPriceGen() always picks up the mocking and works correctly, whether running it alone, or as part of the UT harness (via Run All Tests or Cover All Tests) - all assertions pass.

However, that doesn't apply for TestRollOneDie() - no matter how I call it (via running the UT directly, or Run/Cover All Tests), it fails the Mock.Assert call, saying:
"Expected PriceSeries.RollOneDie(Int32) call on the mock should be once, but it was called 0 time(s)."

Without that Mock.Assert call, it ignores the mock and calls the original implementation of RollOneDie(), and thus fails 5 out of 6 times.

What am I doing wrong?

2 Answers, 1 is accepted

Sort by
0
Stefan
Telerik team
answered on 09 Sep 2013, 10:27 AM
Hi Peter,

Could you wrap your system under test and the two unit tests into an repro project and attach it to this ticket, please? That way it would be much faster to resolve this issue.

Regards,
Stefan
Telerik
Share what you think about JustTrace & JustMock with us, so we can become even better! You can use the built-in feedback tool inside JustTrace, our forums, or our JustTrace or JustMock portals.
0
Peter
Top achievements
Rank 1
answered on 09 Sep 2013, 03:30 PM
Stefan,

Umm... I think the problem was between the keyboard and chair.

Namely, bugs in the UTs themselves that I only spotted when I was prepping the demo project to attach.

[TestMethod]
public void TestFirstPriceGen()
{
    PriceSeries target = new PriceSeries();
    // mock out dice roll
    int[] mockroll = new int[] {3,5,4,5};
    Mock.Arrange(() => target.RollDice(4, 6)).Returns(mockroll);
      
    double expectedPrice = 698.75;  // dice roll of +3 from initialisation
  
    double actualPrice = target.GetNextPrice();
    Assert.AreEqual(expectedPrice,actualPrice);
    Mock.Assert(() => RollDice(4,6),Occurs.Once());
 
}

Which instance's RollDice() method?

[TestMethod]
public void TestRollDice()
{
    PriceSeries target = new PriceSeries();
    Mock.Arrange(() => RollOneDie(6)).Returns(3);
  
    int[] expectedd6 = {3};
    int[] actuald6 = target.RollDice(1, 6);
    Mock.Assert(() => RollOneDie(6), Occurs.Once());
    Assert.AreEqual(expectedd6.Length,actuald6.Length);
    Assert.AreEqual(expectedd6[0],actuald6[0]);        
}


Which instance's RollOneDie() method?


Sorry to waste your time, Stefan - I feel a bit embarrassed to realise that I hadn't specified all the instances that needed to be specified.  Once I fixed those omissions, the UTs run properly every time.

Could you please mark this thread as solved or the like?
Tags
General Discussions
Asked by
Peter
Top achievements
Rank 1
Answers by
Stefan
Telerik team
Peter
Top achievements
Rank 1
Share this question
or