Moq разница между Verify () и Setup () ... VerifyAll () - PullRequest
0 голосов
/ 21 февраля 2019

Я создавал пару модульных тестов, где хотел проверить, вызывается ли метод с параметром, свойства которого я ожидал.

Итак, учитывая эту очень простую систему:

public class Employee
{
    public bool IsEmployed { get; set; }
}

public class DataStore
{
    public void UpdateEmployee(Employee obj)
    {
        // Save in DB
    }
}

public interface IDataStore
{
    void UpdateEmployee(Employee employee);
}

public Employee FireEmployee(IDataStore dataStore, Employee employee)
{
    employee.IsEmployed = false;

    dataStore.UpdateEmployee(employee);

    return employee;
}

Я хочу убедиться, что метод DataStore.UpdateEmployee() вызывается, когда для свойства Employee.IsEmployed установлено значение false.Итак, вот два теста, которые, как я считаю, должны выполнить одно и то же.

[Test]
public void TestViaVerify()
{
    //Arrange
    Mock<IDataStore> dataStore = new Mock<IDataStore>();
    var robert = new Employee { IsEmployed = true };

    //Act
    FireEmployee(dataStore.Object, robert);

    //Assert
    dataStore.Verify(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)), Times.Once);
}

[Test]
public void TestViaSetupVerifyAll()
{
    //Arrange
    Mock<IDataStore> dataStore = new Mock<IDataStore>();
    dataStore.Setup(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)));

    var robert = new Employee { IsEmployed = true };

    //Act
    FireEmployee(dataStore.Object, robert);

    //Assert
    dataStore.VerifyAll();
}

Учитывая текущий код системы, оба теста пройдены, как и ожидалось.

Теперь, скажем, появился другой разработчик и случайно перенес настройку Employee.IsEmployed = false; после метода DataStore.UpdateEmployee().Теперь в этом случае я хочу, чтобы мои тесты не прошли, потому что сотрудник не будет помечен как безработный в БД.

public Employee FireEmployee(IDataStore dataStore, Employee employee)
{
    dataStore.UpdateEmployee(employee);

    employee.IsEmployed = false;

    return employee;
}

Теперь, когда я запускаю тест:

TestViaVerify Проходит

TestViaSetupVerifyAll Fails

Я ожидал, что оба из них не удастся, но похоже на метод TestViaVerify(), лямбда в методе выполняетсяв конце теста, где Employee.IsEmployed уже установлено в false.

Есть ли способ выполнить то, что я хочу, используя метод Verify?И не надо делать настройки ... VerifyAll?Если его нет, я просто пойду с TestViaVerifyAll() подходом.

Ответы [ 2 ]

0 голосов
/ 21 февраля 2019

Это ожидаемое поведение в moq, поскольку аргументы, захваченные вызовом, сравниваются по идентичности, используя Equals, а не по значению.Как только вы изменили захваченные аргументы, вы фактически изменили вызов.Затем, когда вы убедитесь, что эти объекты больше не совпадают.Поскольку @ Old Fox уже предоставил одно решение, я просто добавлю еще одно.Вы можете использовать Verify() вместо VerifyAll(), разница в том, что первый будет проверять только настройки, помеченные как Verifiable().В вашем случае что-то вроде этого:

[Test]
public void TestViaSetupVerifyAll()
{
    //Arrange
    Mock<IDataStore> dataStore = new Mock<IDataStore>();
    dataStore
        .Setup(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)))
        .Verifiable();

    var robert = new Employee { IsEmployed = true };

    //Act
    FireEmployee(dataStore.Object, robert);

    //Assert
    dataStore.Verify();
}

Если вы пометите setup как Verifiable(), вы сможете зафиксировать конкретный вызов с состоянием объекта, который вы на самом деле ожидаете.

0 голосов
/ 21 февраля 2019

Если честно, прошло более 2 лет с тех пор, как в последний раз я обновлялся с исходным кодом moqVerify, и VerifyAll основаны на том, что каждый вызов поддельного экземпляра фиксируется (включая параметры).

Verify будет искать вызов метода / свойства и проверяет захваченные вызовы (сих захваченные параметры), в то время как VerifyAll примет все методы настройки и сделает то же самое, что и метод Verify.

Поскольку захваченный параметр является параметром ByRef, и если последний абзац все еще актуален, вы можетепотому что ваши UT потерпели неудачу просто добавив robert.IsEmployed = true; перед вызовом Verify / VerifyAll:

[Test]
public void TestViaVerify()
{
    ....
    robert.IsEmployed = true; // will make this UT to failed
    //Assert
    dataStore.Verify(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)), Times.Once);
}

[Test]
public void TestViaSetupVerifyAll()
{
    ....
    robert.IsEmployed = true; // will make this UT to failed
    //Assert
    dataStore.VerifyAll();
}

Я думаю, что в прошлом я отвечал на нечто подобное (с большим количеством примеров), как я обошелэта проблема - комбинация между Setup и Callback, так как я не люблю использовать VerifyAll pattern:

....
var invokedCorrectly = false;
dataStore.Setup(x => x.UpdateEmployee(It.Is<Employee>(e => e.IsEmployed == false)))
         .Callback<Employee>(x=> invokedCorrectly = true);

//Act
FireEmployee(dataStore.Object, robert);

//Assert
Assert.IsTrue(invokedCorrectly);
...