Сначала позвольте представить вам мой проект.
Мы разрабатываем приложение, в котором пользователь может работать с программами. Под программами я имею в виду список инструкций для конфиденциального использования.
Существуют различные типы Программ, все они наследуются от абстрактного базового класса Программы.
Поскольку пользователь может создавать различные типы программ, мы разработали ProgramManager, который может создавать любые типы программ по типу. Нам не нужно создавать экземпляр абстрактного класса, но все конкретные классы (и это работает), но поскольку у конкретной Программы есть те же методы (AddNewChannel, Save, ...), мы обрабатываем их как Программы.
Вот пример кода:
public Program CreateProgram(Type type)
{
Program program = Activator.CreateInstance(type) as Program;
program.Directory = ProgramsPath;
int nbChannels = 2; //not 2 but a long line searching the correct number where it is.
for (int i = 1; i <= nbChannels; i++)
{
program.AddNewChannel(i);
}
program.Save();
return program;
}
Теперь мне нужно протестировать эту функцию, и я не хочу дублировать уже выполненные юнит-тесты для различных классов Программы.
В качестве примера, вот одна из моих тестовых функций (для метода Save
) с ее init. Я храню типы, необходимые для тестирования, в файле XML.
[TestInitialize]
public void TestInitialize()
{
if (!TestContext.TestName.StartsWith("GetKnownTypes"))
type = UnitTestsInitialization.applicationHMIAssembly.GetType((string)TestContext.DataRow["Data"]);
}
[TestMethod]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
"|DataDirectory|\\" + DATA_FILE, "Row",
DataAccessMethod.Sequential)]
public void SavedProgramCreatesFile()
{
Program program = Activator.CreateInstance(type) as Program;
program.Name = "SavedProgramCreatesFile";
program.Directory = DIRECTORY;
program.Save();
string savedProgramFileName = program.GetFilePath();
bool result = File.Exists(savedProgramFileName);
Assert.IsTrue(result);
}
Все мои конкретные классы Программы были проверены отдельно.
Таким образом, я хотел бы проверить, вызваны ли следующие методы program.AddNewChannel
и program.Save
.
Я посмотрел на Moq, но первая проблема в том, что метод Save
не является абстрактным.
Кроме того, использование Активатора не позволяет мне сделать Mock<Program>
.
Я попробовал следующее в модульном тесте, чтобы попытаться создать экземпляр макета и использовать его как программу:
[TestMethod]
[DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
"|DataDirectory|\\" + DATA_FILE, "Row",
DataAccessMethod.Sequential)]
public void CreateProgram_CallsProgramSaveMethod()
{
Mock<Program> mock = new Mock<Program>();
mock.Setup(p => p.AddNewChannel(It.IsAny<int>()));
Program program = pm.CreateProgram(mock.Object.GetType());
mock.Verify(p => p.Save());
mock.Verify(p => p.GetFilePath(It.IsAny<string>()));
mock.Verify(p => p.AddNewChannel(It.IsAny<int>()), Times.Exactly(ProgramManager.NB_MACHINE_CHANNELS));
Assert.IsNotNull(program);
program.DeleteFile();
}
Что было вдохновлено этим вопросом: Как издеваться над абстрактным базовым классом
И работает, пока не достигнет строки program.AddNewChannel(i);
в цикле for. Ошибка следующая:
System.NotImplementedException: «Это ошибка DynamicProxy2: перехватчик попытался« продолжить »для метода« Void AddNewChannel (Int32) », который является абстрактным. При вызове абстрактного метода нет реализации, к которой следует «переходить», и перехватчик обязан имитировать реализацию (установить возвращаемое значение, аргументы и т. Д.) '
Кажется, что установка не работает, но я могу понять, почему. (Я пытаюсь создать экземпляр подтипа Proxy, который не реализует метод проверки)
Я также пытался использовать Proxy поверх моего класса программы, который бы реализовывал интерфейс, который содержал бы нужные мне методы, но проблема здесь снова в активаторе.
Может кто-нибудь предложить мне какой-либо способ проверки этих вызовов методов? (Даже если мне нужно изменить мой метод CreateProgram
)
Я посмотрел здесь: Как смоделировать не виртуальные методы? , но я не уверен, что это применимо к моей проблеме.
Я использую MSTests для своих юнит-тестов.
ВНИМАНИЕ
Все остальное работает нормально. Все остальные мои тесты проходят без проблем, и мой код работает (проверено вручную).
Заранее спасибо.