Модульное тестирование класса синтаксического анализатора Xml

#c# #xml #unit-testing

#c# #xml #модульное тестирование

Вопрос:

У меня есть класс, который использует классы XmlReader и XmlReaderSettings в C # для проверки Xml-файлов на соответствие схеме. Поскольку мое приложение включает чтение XML-данных из базы данных, я решаю показать ошибку пользователю в окне сообщения. Таким образом, любые ошибки проверки, а также любые возникшие исключения будут отображаться со строкой «Произошла ошибка при синтаксическом анализе», появляющейся в окне сообщения.

У меня также есть логическая переменная, которая возвращает, был ли синтаксический анализ успешным или нет.

Прямо сейчас я использую логическое значение, возвращаемое функцией Parse в Assert, в то время как функция parse анализирует как допустимые, так и недействительные Xml-файлы.

Таким образом, во время выполнения набора тестовых примеров у меня есть эта стопка окон сообщений, скопившихся в другом окне.

Реальный вопрос, который у меня возник, заключался в том, нормально ли, что несколько таких окон сообщений появляются, в то время как платформа модульного тестирования в Visual Studio сообщает нам, все тесты пройдены или нет.

Или это тот случай, когда мне просто нужно вернуть значение bool, а затем класс GUI отображает соответствующее сообщение об ошибке.

Q2. Также, скажем, если мне действительно нужно проверить, правильно ли была проанализирована конкретная строка и сохранена в массив, могу ли я создать подкласс основного класса, чтобы добавить некоторую функциональность, которая могла бы помочь мне лучше писать модульные тесты?

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

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

Ответ №1:

Разбор Xml и отображение сообщений об ошибках — это отдельные задачи, поэтому ваш анализатор не должен иметь никаких знаний о том, как отображаются сообщения об ошибках.

В зависимости от ваших потребностей, есть несколько вариантов:

Исключения

Я часто живу по правилу: «Если метод не может выполнить свою работу, выдайте исключение». Если вам нужно остановиться при первой ошибке, можно использовать исключения.

С точки зрения модульного тестирования, если вы передаете недопустимые данные, убедитесь, что код выдает исключение, используя атрибут [ExpectedException].

 [TestMethod, ExpectedException(typeof(ParserValidationException))]
public void IllegalDataShouldThrowValidationErrors()
{
    var parser = new MyParser();
    parser.Parse( dataThatContainsErrors );
}
  

Однако, если вам нужно игнорировать недопустимые данные и сообщать об ошибках, вам может потребоваться другой подход.

Специализированный возвращаемый тип

Если вам нужно собрать все ошибки, лучше всего сохранить проанализированный результат и ошибки вместе как объект.

 public class ParsedResult<T>
{
    public T Resu<
    public List<string> Warnings;
}
  

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

 [TestMethod]
public void ParsedResultsForIllegalDataShouldContainWarnings()
{
    var parsedResult = new MyParser.Parse<Foo>( dataThatContainsErrors );

    Assert.IsNotNull(parsedResult);
    Assert.IsNotNull(parsedResult.Result);
    Assert.AreEqual(1, parsedResult.Warnings.Count);
}
  

Отчет об ошибках

Передайте collaborator в объект и попросите его сообщить о своих результатах.

 public ObjectToReturn Parse(string xml, IProgressReporter progress)
{
     // create xml reader
     // read values from xml
     // if a value is invalid, log it
     progress.AddMessage( "property x was invalid. ")
}
  

Отчет о ходе выполнения может быть оболочкой вокруг вашего MessageBox, или это может быть консольный вывод, регистратор и т.д. С точки зрения модульного тестирования, вы можете либо создать тестовый дубль, который фиксирует сообщения, либо вы можете использовать макет фреймворка и убедиться, что он вызывался определенное количество раз. Вот пример, в котором используется Moq.

 var mockReporter = new Mock<IProgressReporter>();
IProgressReporter reporter = mockReporter.Object;

var parser = new MyParser();
var illegalData = // your illegal data;

var result = parser.Parse( illegalData, parser);

Assert.IsNotNull(result, "The value was not parsed correctly.");
mockReporter.Verify( r => r.AddMessage( It.IsAny<string>() ), Times.AtLeast(1));
  

Ответ №2:

Я думаю, вам не следует использовать MessageBox для сообщения об ошибках, а вместо этого передавать ошибки как List<string> и отображать их в графическом интерфейсе.

Мне нравится разработка, основанная на тестировании, но написание тестов после написания реализации тоже работает. Для меня их написание требует больше усилий.