TL; DR, вопрос:
Какое влияние на выполнение кода может иметь наличие метода расширения в .NET(например, JIT/optimizations)?
Фон
Я испытываю неудачу теста в MSTest, которая зависит от того, проверена ли, по-видимому, неродственная сборка.
Я заметил ошибку теста и случайно заметил, что сбой произошел только в том случае, если была загружена другая тестовая сборка. Запуск mstest на сборках тестов Unittests и Integration начнет выполнение тестов интеграции и завершится неудачей в 21-м тесте интеграции в 4.5 CLR, тогда как это не произойдет в версии 4.0 CLR (в той же конфигурации в противном случае). Я удалил все тесты, но отказался от сборки тестирования интеграции. Выполнение теперь выглядит так, как при загрузке обеих тестовых сборок, mstest загружает обе сборки, а затем выполняет один тест в сборке тестов интеграции, что не удается.
> mstest.exe /testcontainer:Unittests.dll /testcontainer:IntegrationTests.dll
Loading C:\Proj\Tests\bin\x86\Release\Unittests.dll...
Loading C:\Proj\Tests\bin\x86\Release\Integrationtests.dll...
Starting execution...
Results Top Level Tests
------- ---------------
Failed Proj.IntegrationTest.IntegrationTest21
Без сборки Unittests при выполнении теста проходит.
> mstest.exe /testcontainer:IntegrationTests.dll
Loading C:\Proj\Tests\bin\x86\Release\Integrationtests.dll...
Starting execution...
Results Top Level Tests
------- ---------------
Passed Proj.IntegrationTest.IntegrationTest21
Я думал, что это должна быть вещь [AssemblyInitialize]
, выполняемая в dll UnitTests, или, возможно, какое-то статическое состояние в Unittest.dll или общая зависимость, которая изменяется при загрузке тестовой сборки. В Unittests.dll я не нахожу ни статических конструкторов, ни сборки init. Я подозревал разницу в развертывании, когда сборка Unittests была включена, (зависимая сборка была развернута в другой версии и т.д.), Но я сравнивал управляющие/отказоустойчивые серверы развертывания, и они являются двоичными эквивалентами.
Итак, какая часть сборки Unittests вызывает разницу в тестах? Из модульных тестов я удалял половину тестов за раз, пока я не свернул его до исходного файла в сборке модулей. Наряду с тестовым классом объявляется метод расширения:
Помимо этого класса расширений сборка Unittest теперь содержит один тестовый пример в фиктивном тестовом классе. Сбой теста происходит только в том случае, если у меня есть метод фиктивного теста и объявлен метод расширения. Я мог бы удалить всю оставшуюся тестовую логику, пока DLL Unittest не будет одним файлом, содержащим это:
// DummyTest.cs in Unittests.dll
[TestClass]
public class DummyTest
{
[TestMethod]
public void TestNothing()
{
}
}
public static class IEnumerableExtension
{
public static IEnumerable<T> SymmetricDifference<T>(
this IEnumerable<T> @this,
IEnumerable<T> that)
{
return @this.Except(that).Concat(that.Except(@this));
}
}
Если либо тестовый метод, либо класс расширения удалены, тест проходит. Оба присутствуют, и тест терпит неудачу.
Нет вызовов метода расширения, сделанного из любой сборки, и ни один код не выполняется в сборке Unittests до того, как будут выполнены тесты интеграции (насколько мне известно).
Я уверен, что интеграционный тест достаточно сложный, что различия в оптимизации JIT могут привести к различию, например. в плавающей запятой. Это то, что я вижу?