Я использую MoQ в C # для выполнения модульных тестов / BDD-тестов, и мне часто нужно генерировать один и тот же объект дважды (потому что он потенциально будет использоваться в словаре). Или что-то на 99% то же самое, но только с другим идентификатором.

Есть ли способ «клонировать» определение Mock? Или создать два объекта с одинаковым определением?

1
J4N 24 Апр 2017 в 10:32

2 ответа

Лучший ответ

Вы должны создать вспомогательный метод, который создает некоторые параметры для создания объекта Mock.

[Test]
public void MyTest()
{
    Mock<ITestObject> myMock = CreateObject(1);
    ITestObject obj = myMock.Object;
}

private Mock<ITestObject> CreateObject(int id)
{
    Mock<ITestObject> mock = new Mock<ITestObject>();
    mock.SetupGet(o => o.ID).Returns(id);
    return mock;
}

private interface ITestObject
{
    int ID { get; set; }
}
1
Matthiee 24 Апр 2017 в 07:54

Если вам просто нужен набор данных для модульного тестирования, вы можете рассмотреть что-то вроде AutoFixture. Он может работать с Moq в случае классов, которые вы хотите смоделировать. Вы учите AutoFixture, как создавать YourClass, и вы даже можете устанавливать правила, такие как «мои идентификаторы должны быть строками с заглавными буквами и не более X раз их».

Тогда вы просто используете автокрепление.

var fixture = new Fixture();
var tetsClasses = fixture.CreateMany<TestClass>();

Это действительно просто, чтобы дать вам идею. Вы можете сделать с ним гораздо больше, и он хорошо играет с Moq.

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

internal class TestClassBuilder<T> : where T : TestClass
{
   int Id {get; set;}

   public T WithId(int id)
   {
     this.Id = id;
     return this;
   }

   public virtual T Build()
   {      
        return new T()
         {
           if(this.Id)
               Id = this.Id; // if you chose to set it, then assign it
           else
            Id = GetRandomId() // you can figure a solution here
         }
    }  
}

Тогда назовите это как:

var stubOne = TestClassBuilder.WithId(1).Build();

Вы можете расширить его, чтобы создать список, если хотите.

Мне нравятся свободно распространяемые API на сборщиках данных, потому что вы можете начать рассказывать свою историю с помощью методов, которые вы создаете, и она поддерживает раздел Arrange в чистоте и порядке. Пример:

var UnderAgeCustomer = new CustomerBuilder
                        .UnderAge
                        .WithFakeId
                        .InACrowd
                        .LooksYoung
                        .Build()

Вы могли бы даже добавить на

public static implicit operator T(TestClassBuilder<T> builder)
{
  return builder.Build();
}

И вам не нужно будет постоянно использовать часть .Build () (я думаю, что сборка добавляет ненужный шум). Только не пытайтесь присвоить это переменной, это не сработает.

TestClass MockTwo = TestClassBuilder.WithId(2);

Я бы сказал, что вы также можете использовать шаблон фиксации для отслеживания всего этого ... но между этим и сборщиком данных вы также можете использовать AutoFixture и Moq, как я и предлагал :)

0
Angelo 12 Май 2017 в 16:50
43582225