Ложноотрицательный модульный тест с Pex, Contracts и QuickGraph

все. У меня сложное взаимодействие между контрактами, pex и quickgraph, и я был бы очень благодарен за совет от более знающих. Я свел это к случаю воспроизведения, когда комментирование одного контракта устраняет ложноотрицательный результат, но я не смог диагностировать его с помощью отладчика за отведенное время, потому что код объекта (quickgraph) имеет побочные эффекты в свойстве - геттеры, что означает, что отладчик выполняет побочные эффекты при отображении значений свойств, влияя на фактический порядок выполнения.

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

Я установил Pex & Moles

http://research.microsoft.com/en-us/projects/pex/downloads.aspx

и CodeContracts для .NET 4.0

http://research.microsoft.com/en-us/projects/contracts/

Я загрузил через nuget самую последнюю версию QuickGraph, которая полностью построена для .NET 3.5. Я сократил его до необходимого мне минимума, вошел в свойства проекта для всех, обновил их все до .NET 4.0 из профиля клиента .NET 3.5, исправил одно критическое изменение источника (что было тривиально и очень, очень маловероятно, чтобы иметь какое-либо соединение с моим проблема). Затем я перешел на вкладку «Контракты кода» на каждой странице проекта и включил все статические и динамические параметры.

http://quickgraph.codeplex.com/releases/view/55262

В проекте 192 юнит-теста, многие из которых сгенерированы Pex (очень красиво!). Чтобы запустить тесты, загрузите zip-файл моего проекта из

http://dl.dropbox.com/u/1997638/QuickGraph.zip

Убедитесь, что у вас есть Pex & Moles и Contracts по ссылкам выше. Откройте решение, перестройте все, затем на уровне решения «Запустить все тесты в решении» (Ctrl-R, A). Все пройдет. Затем перейдите к строке 49 файла IImplicitUndirectedGraphContracts.cs и раскомментируйте Контракт под большим комментарием (добавленным мной). Один тест, Prim12240WithDelegate, завершится ошибкой.

В этом тесте используется конструктор графа, который на лету строит ребра, вызывая предоставленный пользователем делегат в средствах получения свойств для Edges и EdgeCount. Милый. Но что-то идет не так с Контрактом в строке 49 IImplicitUndirecteGraphContracts.cs.

Это ложноотрицательный результат, потому что, если я закомментирую этот контракт, тест пройдёт. Пытаясь проследить это в отладчике, это как-то связано со временем создания краев в средствах получения свойств. Однако я не смог распутать это, потому что отладчик вызывает эти геттеры, код объекта вызывает их, код контрактов вызывает их, может быть, статически, может быть, динамически, я просто потерялся, пытаясь следовать за ним, и подумал, что я Подниму вопрос к тем, кто лучше меня разбирается в деталях исполнения контрактов.

Вот оскорбительный контракт; комментирование этого делает модульный тест успешным:

[Pure]
  IEnumerable<TEdge> IImplicitUndirectedGraph<TVertex, TEdge>.AdjacentEdges(TVertex v)
  {
    IImplicitUndirectedGraph<TVertex, TEdge> ithis = this;
    Contract.Requires(v != null);
    Contract.Requires(ithis.ContainsVertex(v));
    Contract.Ensures(Contract.Result<IEnumerable<TEdge>>() != null);
~~~~~~> Contract.Ensures(
      Enumerable.All(
        Contract.Result<IEnumerable<TEdge>>(),
        edge => 
          edge != null && 
          ithis.ContainsEdge(edge.Source, edge.Target) && 
          (edge.Source.Equals(v) || edge.Target.Equals(v))
        )
      );
    return default(IEnumerable<TEdge>);
  }

person Reb.Cabin    schedule 30.01.2011    source источник


Ответы (1)


У Pex есть проблемы с выражениями LINQ в среде выполнения .NET 4.0. из первого ответа на это сообщение форума MSDN подробнее:

Наша поддержка Linq работает для .NET 2.0 / 3.5, но, похоже, у нас есть регресс для .NET4.0. Если вы используете 4.0, это объясняет, почему Pex не может генерировать интересные тестовые примеры - мы неправильно инструментируем Linq.

Почему Pex все равно борется с Linq: вкратце, Linq использует DynamicMethod для генерации кода. О методах DynamicMethod не сообщается профилировщику, когда они не работают. Поскольку наш профилировщик не может внедрять обратные вызовы в DynamicMethod, Pex не может отслеживать поток данных через запрос Linq. У нас есть обходной путь, который перехватывает внутреннюю часть компилятора Linq to Object и заставляет его использовать вместо него Reflection.Emit.

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

person Ryan Gross    schedule 24.07.2011