В идеале тесты не должны взаимодействовать с 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);
// ...
}
person
Enrico Campidoglio
schedule
14.10.2013