How to verify that a method has been called a specific number of times using Moq?

I have the following implementation,

public interface IMath {
    double Add(double a, double b);
    double Subtract(double a, double b);
    double Divide(double a, double b);
    double Multiply(double a, double b);
    double Factorial(int a);
}

public class CMath: IMath {
    public double Add(double a, double b) {
        return a + b;
    }

    public double Subtract(double a, double b) {
        return a - b;
    }

    public double Multiply(double a, double b) {
        return a * b;
    }

    public double Divide(double a, double b) {
        if (b == 0)
            throw new DivideByZeroException();
        return a / b;
    }

    public double Factorial(int a) {
        double factorial = 1.0;
        for (int i = 1; i <= a; i++)
            factorial = Multiply(factorial, i);
        return factorial;
    }
}

How to check what Multiply()is called n times when n Factorial is calculated ?

I am using NUnit 3 and Moq. Below are the tests I already wrote,

[TestFixture]
public class CMathTests {

    CMath mathObj;

    [SetUp]
    public void Setup() {
        mathObj = new CMath();
    }

    [Test]
    public void Add_Numbers9and5_Expected14() {
        Assert.AreEqual(14, mathObj.Add(9, 5));
    }

    [Test]
    public void Subtract_5From9_Expected4() {
        Assert.AreEqual(4, mathObj.Subtract(9, 5));
    }

    [Test]
    public void Multiply_5by9_Expected45() {
        Assert.AreEqual(45, mathObj.Multiply(5, 9));
    }

    [Test]
    public void When80isDividedby16_ResultIs5() {
        Assert.AreEqual(5, mathObj.Divide(80, 16));
    }

    [Test]
    public void When5isDividedBy0_ExceptionIsThrown() {
        Assert.That(() => mathObj.Divide(1, 0),
            Throws.Exception.TypeOf<DivideByZeroException>());
    }

    [Test]
    public void Factorial_Of4_ShouldReturn24() {
        Assert.That(mathObj.Factorial(4), Is.EqualTo(24));
    }

    [Test]
    public void Factorial_Of4_CallsMultiply4Times() {

    }
}

I am new to using Moq, so I did not quite understand it at the moment.

+4
source share
3 answers

You need to separate the bullying part and the tested part, because Moq is the removal of dependencies, and your CMath class does not have them!

, Multiply 4 - . :)


1 -

Factorial, .

 public interface IMath {
        double Add(double a, double b);
        double Subtract(double a, double b);
        double Divide(double a, double b);
        double Multiply(double a, double b);      
    }
 public interface IFactorial {
       double Factorial(int a, IMath math);
}

Mock IMath

[Test]
public void Factorial_Of4_CallsMultiply4Times()
{
    var mathMock = new Mock<IMath>();
    var factorial = new Factorial();
    factorial.Factorial(4, mathMock.Object);
    mathMock.Verify(x => x.Multiply(It.IsAny<double>()), Times.Exactly(4));
}

2 -

public double Factorial(int a, Func<double,double,double> multiply = null)
{
    multiply = multiply ?? CMath.Multiply;
    double factorial = 1.0;
    for (int i = 1; i <= a; i++)
        factorial = multiply(factorial, i);
    return factorial;
}


[Test]
public void Factorial_Of4_CallsMultiply4Times()
{
    var mathMock = new Mock<IMath>();
    var math = new CMath();
    math.Factorial(4, mathMock.Object.Multiply);
    mathMock.Verify(x => x.Multiply(It.IsAny<double>()), Times.Exactly(4));
}
+5

@aershov, , Multiply 4 . , Factorial_Of4_ShouldReturn24. , TestCase, , :

[TestCase(4, 24)]
[TestCase(2, 2)]
[TestCase(1, 1)]
[TestCase(0, 1)]
public void Factorial_OfInput_ShouldReturnExpected(int input, int expectedResult)
{
    Assert.That(mathObj.Factorial(input), Is.EqualTo(expectedResult));
}

@aershov , , . , , - Multiply virtual. . :

public class CMath : IMath
{
    public virtual double Multiply(double a, double b)
    {
        return a * b;
    }
    // ...

Test

Mock<CMath> mockedObj;
CMath mathObj;

[SetUp]
public void Setup()
{
    mockedObj = new Mock<CMath>();
    mockedObj.CallBase = true;
    mathObj = mockedObj.Object;
}

[Test]
public void Factorial_Of4_CallsMultiply4Times()
{
    mathObj.Factorial(4);
    mockedObj.Verify(x => x.Multiply(It.IsAny<double>(), 
                                     It.IsAny<double>()), Times.Exactly(4));
}

( , - ), , .

Mocks , , , , . , :

public double Factorial(int a)
{
    double factorial = 1.0;
    for (int i = 1; i <= a; i++)
        factorial = Multiply(factorial, a);
    return factorial;
}

, , . , , . , .

, , Factorial. 4!. : 4*3*2*1, 1 NOP, n*1=n. , :

public double Factorial(int a)
{
    double factorial = 1.0;
    for (int i = 2; i <= a; i++)
        factorial = Multiply(factorial, i);
    return factorial;
}

/ , Mocked, Multiply, , 3 .

.

+4

using Math.Library;
using System;
using Moq;
using NUnit.Framework;

namespace UnitTests {
[TestFixture]
public class CMathTests {

    CMath mathObj;
    private IMath _math;
    [SetUp]
    public void Setup() {
        mathObj = new CMath();// no need for this in mocking and its a wrong      approach
        _math = new Mock<IMath>();//initialize a mock object
    }

    [Test]
    public void Add_Numbers9and5_Expected14() {
        Assert.AreEqual(14, mathObj.Add(9, 5));
    }

    [Test]
    public void Subtract_5From9_Expected4() {
        Assert.AreEqual(4, mathObj.Subtract(9, 5));
    }

    [Test]
    public void Multiply_5by9_Expected45() {
        Assert.AreEqual(45, mathObj.Multiply(5, 9));
    }

    [Test]
    public void When80isDividedby16_ResultIs5() {
        Assert.AreEqual(5, mathObj.Divide(80, 16));
    }

    [Test]
    public void When5isDividedBy0_ExceptionIsThrown() {
        Assert.That(() => mathObj.Divide(1, 0),
            Throws.Exception.TypeOf<DivideByZeroException>());
    }

    [Test]
    public void Factorial_Of4_ShouldReturn24() {
        Assert.That(mathObj.Factorial(4), Is.EqualTo(24));
    }

    [Test]
    public void Factorial_Of4_CallsMultiply4Times() {
    int count = 0;
    _math.setup(x =>x.Multiply(It.IsAny<Int>(),It.IsAny<Int>())).Callback(() => count++);
    _math.verify(x =>x.Multiply(),"Multiply is called"+ count+" number of times");
    }
}
}

. , , , , ., mock- .

Moq,

-1

All Articles