Moq setup возвращает ссылку на объект - PullRequest
0 голосов
/ 29 апреля 2020

Допустим, у меня есть простой класс с именем MyRequestHandler, и у него есть метод с именем ProcessRequest, который просто принимает объект запроса, сопоставляет его с возвращаемым объектом и возвращает этот объект. (Это, очевидно, очень простой пример гораздо более сложного метода / теста, над которым я работаю).

public class MyRequestHandler
{
  private IMapper _mapper;

  public MyRequestHandler(IMapper maper)
  {
    _mapper = mapper;
  }

  public MyReturnObject ProcessRequest(MyRequestObject requestObject)
  {
    MyReturnObject returnObject = _mapper.Map<MyReturnObject>(requestObject);
    return returnObject;
  }
}

Теперь для модульного тестирования (с использованием Xunit) я хочу протестировать метод ProcessRequest, но, разумеется, мы хотим использовать метод Map для Moq:

MyRequestObject requestObject = new RequestObject()
{
  RequestInt = 1,
  RequestString = "Hello"
};

MyReturnObject returnObject = new MyReturnObject()
{
  MyInt = 1,
  MyString = "Hello"
};

Mock<IMapper> mockMapper = new Mock<IMapper>();
mockMapper.Setup(m => m.Map<MyRequestObject>(requestObject)).Returns(returnObject);

MyRequestHandler requestHandler = new MyRequestHandler(mockMapper.Object);
MyReturnObject response = requestHandler.ProcessRequest(requestObject);

Assert.Equal(returnObject.MyInt, response.MyInt);
Assert.Equal(returnObject.MyString, response.MyString);

Проблема здесь в том, что Moq возвращает (и я думаю, должно быть очевидно, что это так) ссылку на returnObject, поэтому мои Asserts всегда будут пройти, даже если мой метод должен был изменить значение до возврата объекта. Теперь я могу создать новый MyReturnObject в Moq Setup / Return и сравнить MyInt и MyString по значениям, которые я присваиваю новому, но что если это действительно сложный объект с 20 свойствами и списками объектов? Может быть, я хочу использовать AutoFixture для создания возвращаемого объекта и использовать DeepEqual для их сравнения? Это вообще возможно? Я смотрю на это неправильно, или мне нужно выполнить какое-либо клонирование в меню «Настройка / возврат», чтобы это работало?

Ответы [ 2 ]

1 голос
/ 29 апреля 2020

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

Параметры:

  • убедитесь, что возвращаемые объекты неизменяемость - либо путем того, что они будут неизменными для запуска, либо путем возврата интерфейса без «set» методов с экземпляром, созданным с помощью mocks
  • , создайте отдельный экземпляр для «ожидаемых» и «mocked» значений, а затем сравните свойство по имущество. Для этого есть множество вспомогательных библиотек (мне нравится FluentAssertions).
  • просто утверждает отдельные свойства вместо сравнения объектов - отлично работает для небольшого числа полей.

Если возможно Я бы предпочел неизменяемые объекты - это предотвращает возможность написания неправильного кода и, следовательно, уменьшает количество необходимого тестирования.

0 голосов
/ 29 апреля 2020

В этом случае вы не получили новые данные и можете проверить поведение

Внутреннее состояние не имеет значения в этом случае

var requestObject = new RequestObject();
var returnObject = new MyReturnObject();

...
var actual = requestHandler.ProcessRequest(requestObject);

Assert.AreSame(returnObject, actual);
mockMapper.Verify(
   instance => instance.Map<MyRequestObject>(requestObject),
   Times.Once);

Некоторые детали

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

    publi c class MyRequestObject {int RequestInt {get; приватный набор; } string RequestString {get; приватный набор; }}

в противном случае вы всегда должны проверять наличие мутаций параметров. Вы можете вообразить 10 участников, вызванных в глубину, и каждый из них должен пройти такие тесты Эти тесты будут слабы от изменений, они ничего не делают с новыми свойствами.

Лучше иметь хорошее соглашение о кодировании и иногда делать просмотр кода. Например, кто-то может случайным образом удалить private из свойства, и его нельзя отследить никакими тестами.

В примере есть много хороших практик "написать тест перед код "и т. д.

...