У меня есть интерфейс ILogger с LogTrace (строковое значение, параметры объекта params []). Теперь я хочу убедиться, что LogTrace вызван и строка для регистрации содержит некоторый идентификатор. Проблема в том, что это можно называть по-разному. Например. 1) LogTrace ("MyString" + id) 2) LogTrace ("MyString {0}", id) и так далее.

Есть ли хороший способ с Moq проверить все сценарии? Я могу думать только о создании собственного макета, который будет форматировать строку, которая будет доступна для проверки.

15
Ilya Chernomordik 12 Фев 2014 в 17:29

3 ответа

Лучший ответ
mock.Verify( m => m.LogTrace( It.IsAny<string>(), It.IsAny<object[]>() ) );

params object[] в любом случае передается методу как object[], поэтому вам просто нужно каким-то образом сопоставить массив (как, например, выше, это принимает все).

Если вам нужно больше контроля над списком, используйте сопоставитель It.Is, который позволяет вам создать свой собственный предикат:

 mock.Verify( m => m.LogTrace( It.IsAny<string>(),
            It.Is<object[]>(ps =>
                ps != null &&
                ps.Length == 1 &&
                ps[0] is int &&
                (int)ps[0] == 5
            ) ) );

В этом примере показано, как проверить, не является ли список параметров пустым и содержит ли 5 в качестве единственного параметра типа int.

17
Wiktor Zychla 12 Фев 2014 в 14:01

Вы можете попробовать использовать Callback, но он будет довольно запутанным (не протестирован):

var mock = new Mock<ILogger>();
string trace = null;
mock.Setup(l => l.LogTrace(It.IsAny<string>(), It.IsAny<object[]>()))
        .Callback((s1, par) =>
            {
                trace = string.Format(s1, par);
            });

//rest of the test

Assert.AreEqual(expected, trace);

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

1
Grzenio 12 Фев 2014 в 13:41

Я не думаю, что здесь есть простой способ сделать то, что вам нужно. Проблема в том, что вам нужно убедиться, что в ваш метод будет передана определенная комбинация значений, что приводит к множеству различных проверяемых сценариев:

  • Строка содержит ID И параметры содержат ID - пройти
  • Строка содержит ID И параметры не содержат ID - пройти
  • Строка не содержит ID И параметры содержат ID = pass
  • Строка не содержит ID И параметры не содержат ID - сбой

Однако Moq не поддерживает такого рода условные выражения между различными аргументами вашего проверяемого метода. Одно из возможных решений - проверить отсутствие идентификатора вместо его присутствия в любом аргументе. Попробуйте что-нибудь вроде:

mock.Verify(m => m.LogTrace(
    It.Is<string>(s => !s.Contains(id)), 
    It.Is<object[]>(o => !o.Contains(id))), Times.Never());

Здесь мы проверяем, выполняется ли когда-либо условие fail , то есть ваша строка не содержит идентификатора, как и ваш массив объектов. Мы используем Times.Never (), чтобы убедиться, что такой ситуации никогда не должно произойти.

Однако имейте в виду, что код может быть неочевидным на первый взгляд; убедитесь, что вы правильно объяснили свое намерение после того, как напишите его.

2
rla4 12 Фев 2014 в 17:34