Хотя уже принят принятый ответ (ПРИМЕЧАНИЕ: он изменился с тех пор, как я первоначально разместил) , я хотел бы предложить альтернативный способ использования отражения. Разделите метод тестирования на два метода: метод трамплина и универсальный метод теста . Есть несколько преимуществ:
Общий тестовый метод больше похож на любой другой тестовый метод. Это не имеет смешанного отражения.
Обычный метод испытаний может проходить обычным образом, в том числе и потому, что в нем нет смешанного отражения.
Изменения в тестируемом компоненте с большей вероятностью вызовут ошибку компилятора в тестовом проекте, поэтому вы знаете, что необходимо обновить общий тестовый метод и, вероятно, метод трамплина. Кроме того, из-за того, где генерируется исключение, во время выполнения становится понятнее, что это связано с отражением поддержки, а не с тем, как используется компонент.
Методу трамплинов не нужно ничего знать о тестируемом компоненте, только как вызвать универсальный метод теста.
Шаблон может быть легко и последовательно воспроизведен, потому что есть очень мало изменений.
Вот пример, основанный на вопросе и принятом ответе:
[TestCase(typeof(CalendarGeneralCsv), typeof(CalendarGeneralCsvMap), 121)]
[TestCase(typeof(CalendarCustomCsv), typeof(CalendarCustomCsvMap), 80)]
public void ReadFromCsvFileWithConfigurationMapTest(Type t, Type tmap, int totalRowsExpected)
{
GetType().GetMethod(nameof(GenericReadFromCsvFileWithConfigurationMapTest))
.MakeGenericMethod(t, tmap) // <-- Type parameters go here
.Invoke(this, new object[] { totalRowsExpected }); // <-- inputs go here
}
public void GenericReadFromCsvFileWithConfigurationMapTest<T, Tmap>(int totalRowsExpected)
where T : class
where Tmap : class
{
// Arrange
// Act
var records = csvService.ReadFileCsv<T, Tmap>(_csvToRead, ",") as IEnumerable<object>;
// Assert
records.Should().NotBeNull();
var result = new List<object>(records);
result.Should().NotBeNullOrEmpty();
result.Should().HaveCount(totalRowsExptected);
}
Достопримечательности
Используется GetType()
, потому что он ищет метод того же типа (тестовый класс). Это уменьшает вариации, так что рисунок можно легче воспроизвести.
Общий метод test имеет другое имя (неважно, какое оно есть, если он другой), поэтому при вызове GetMethod
не нужно указывать типы параметров. Должен быть только один метод с таким именем, и он общедоступен, поэтому ему также не требуется BindingFlags
. Кроме того, вы можете сделать его приватным, просто добавьте BindingFlags.NonPublic | BindingFlags.Instance
. Примечание: не все версии фреймворка имеют перегрузку, принимающую BindingFlags
. Вам нужно будет найти альтернативу, если вы хотите сделать ее приватной.
Общий метод испытаний должен включать ограничения. Это делает ограничения формальной частью вашего теста. Отражение не будет выполнено во время выполнения в любом случае, если ограничения не будут соблюдены, но, имея их в общем методе тестирования, вы, вероятно, напишите лучший тест с самого начала. Вы упомянули, что T
и Tmap
должны быть ссылочными типами, поэтому они включены выше.
Наконец, ваш трамплин способен определять несколько тестовых случаев, поскольку вы указали, что должны это делать, поэтому я включил еще один календарь и отображение выше.