AutoFixture создать свойство с внутренним сеттером
Есть ли какой-то способ позволить AutoFixture создавать свойства с помощью внутреннего установщика?
Я посмотрел на источник AutoFixture и обнаружил, что в AutoPropertiesCommand метод GetProperties проверяет, имеет ли свойство GetSetMethod()!= Null. С внутренним установщиком это возвращает нуль, если вы не установите аргумент ignorePublic в true.
Самой простой вещью, конечно, было бы сделать сеттер публичным, но в проекте, над которым я работаю, просто не было бы правильного решения.
Ниже приведен упрощенный фрагмент кода проекта в качестве примера.
public class Dummy
{
public int Id { get; set; }
public string Name { get; internal set; }
}
public class TestClass
{
[Fact]
public void Test()
{
var dummy = new Fixture().Create<Dummy>();
Assert.NotNull(dummy.Name);
}
}
1 ответ
В идеале тесты не должны взаимодействовать с internal
члены класса, поскольку они явно исключены из его общедоступного API. Вместо этого эти члены будут косвенно проверяться путями кода, инициированными через общедоступный API.
Однако, если это невозможно в вашей конкретной ситуации, возможный обходной путь может заключаться в явном присвоении значения внутренним свойствам из тестов.
Вы можете сделать это одним из двух способов:
- Выставив все внутренние элементы в сборке для тестового проекта, используя
InternalsVisibleTo
приписывать. - Представляяизменяемое состояние класса в определенном интерфейсе и реализуя это явно.
В вашем примере вариант 1 будет:
// [assembly:InternalsVisibleTo("Tests")]
// is applied to the assembly that contains the 'Dummy' type
[Fact]
public void Test()
{
var fixture = new Fixture();
var dummy = fixture.Create<Dummy>();
dummy.Name = fixture.Create<string>();
// ...
}
Вариант 2 вместо этого будет выглядеть примерно так:
public class Dummy : IModifiableDummy
{
public string Name { get; private set; }
public void IModifiableDummy.SetName(string value)
{
this.Name = value;
}
}
[Fact]
public void Test()
{
var fixture = new Fixture();
var dummy = fixture.Create<Dummy>();
((IModifiableDummy)dummy).SetName(fixture.Create<string>());
// ...
}
Вариант 1 довольно быстро реализуется, но имеет побочный эффект открытиявсех внутренних элементов в сборке, что может быть не тем, что вам нужно.
Вариант 2, с другой стороны, позволяет вам контролировать, какая часть состояния объекта должна отображаться как изменяемая, при этом сохраняя его отделенным от собственного публичного API объекта.
В качестве примечания хочу отметить, что, поскольку вы используете xUnit, вы можете воспользоваться поддержкой AutoFixture для теорий данных, чтобы сделать свои тесты несколько более краткими:
[Theory, AutoData]
public void Test(Dummy dummy, string name)
{
((IModifiableDummy)dummy).SetName(name);
// ...
}
Если вы предпочитаете установить Name
свойство к известному значению, сохраняя при этом остальную часть Dummy
объект анонимный, у вас также есть возможность объединить два в одной теории данных:
[Theory, InlineAutoData("SomeName")]
public void Test(string name, Dummy dummy)
{
((IModifiableDummy)dummy).SetName(name);
// ...
}