Можно ли использовать контекст логического вызова в модульном тесте в VS 2010? - PullRequest
15 голосов
/ 26 марта 2011

Можно ли сделать этот тест не исключением? Похоже, что добавление любого класса без GAC в контекст логического вызова вызывает исключение в строке 2 теста.

Test 'TestProject1.UnitTest1.TestMethod1' не удалось: метод теста TestProject1.UnitTest1.TestMethod1 бросил исключение: System.Configuration.ConfigurationErrorsException: Произошла ошибка при загрузке файл конфигурации: тип не решено для члена «TestProject1.Bar, TestProject1, Версия = 1.0.0.0, Культура = нейтральная, PublicKeyToken = нуль. ---> System.Runtime.Serialization.SerializationException: Тип не разрешен для члена «TestProject1.Bar, TestProject1, Версия = 1.0.0.0, Культура = нейтральная, PublicKeyToken = нуль».

namespace TestProject1 {
    [ Serializable]
    public class Bar {

    }

    [TestClass]
    public class UnitTest1 {
        [TestMethod]
        public void TestMethod1() {
            CallContext.LogicalSetData("foo", new Bar());
            ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None );
        }
    }
}

ПОЧЕМУ?!?!?

Ответы [ 4 ]

26 голосов
/ 29 марта 2011

По сути, это проблема дизайна процесса, используемого для размещения тестового кода во время тестового прогона. Тесты запускаются в отдельном домене приложений от домена приложений по умолчанию для хоста тестирования. Когда выполняется вызов из одного домена приложений в другой, контекст вызова необходимо десериализовать в целевой домен приложений. В вашем случае ConfigurationManager.OpenExeConfiguration заканчивает тем, что звонит AppDomain.get_Evidence. Это приводит к вызову из домена приложений, на котором размещены тесты, в домен приложений по умолчанию.

Базовый каталог AppDomain по умолчанию - это то место, куда был установлен исполняемый файл тестового хоста. По умолчанию это "% ProgramFiles% \ Microsoft Visual Studio 10.0 \ Common7 \ IDE" . Домен приложений, в котором размещаются тесты, использует базовый каталог расположения развертывания тестового запуска. По умолчанию это " \ TestResults \ \ Out" . Таким образом, домен AppDomain, используемый для запуска тестов, может разрешать сериализованные типы, поскольку их сборки находятся в каталоге Out (независимо от того, они уже загружены в AppDomain теста, поскольку этот код выполняется), в то время как AppDomain по умолчанию не может.

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

Другим возможным решением было бы скопировать сборки в путь поиска домена приложения по умолчанию. Это будет базовый каталог, перечисленный выше, и privatePath, перечисленные в QTAgent.exe.config или QTAgent32.exe.config (который запускается, зависит от того, используете ли вы 64-разрядную операционную систему и настройки платформы хостинга в настройки теста). Как и для всех частных путей поиска, эти каталоги должны быть подкаталогами базового каталога. Вы можете создать новый подкаталог с соответствующими правами доступа, добавить имя каталога в privatePaths в файлах .exe.config, а затем скопировать сборки, содержащие сериализованные типы, в этот каталог во время настройки теста. Это решение не требует административных привилегий или строгого именования, если каталог, в который вы копируете сборки, позволяет вам писать в него.

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

Редактировать : если вы выберете одно из этих «решений», вам также нужно будет отключить процесс хоста тестирования, чтобы он оставался в живых между тестовыми запусками. Это связано с тем, что AppDomain по умолчанию останется на месте, а сборки, содержащие сериализованные типы, останутся загруженными, что не позволит вам обновить их при следующем тестовом запуске. Опция для управления этим: «Поддерживать работу механизма выполнения теста между тестовыми прогонами» в разделе «Инструменты -> Параметры -> Инструменты тестирования -> Выполнение теста».

11 голосов
/ 09 января 2014

Эта проблема может быть решена с помощью Bar, реализующего MarshalByRefObject.Это позволяет ссылаться на класс в AppDomain, внутри которого выполняется тестовый прогон.

[ Serializable]
public class Bar : MarshalByRefObject {

}
9 голосов
/ 22 августа 2012

При использовании логического CallContext для хранения объектов реализуйте соответствующую логику финализации (IDisposable) для очистки объектов, хранящихся в CallContext (например, CallContext.FreeNamedDataSlot)

Надеюсь, это поможет,

Juanjo

0 голосов
/ 27 июня 2018

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

В моем случае службы WCF и WebAPI размещались в тестовой среде самостоятельно, чтобы иметь высокий контроль над своим поведением (например, заменять компоненты в контейнере IoC), но имели это исключение сериализации, когда выполнение достигло аутентификации через Active Directory,С помощью инструмента отражения (например, IL Spy) я мог определить раздел конфигурации (system.directoryservices), который AD пытался прочитать, и вызвал проблему междоменной сериализации.

Размещение следующего кода перед запуском автономных служб решило проблему:

System.Configuration.ConfigurationManager.GetSection("system.directoryservices");

Более подробные объяснения здесь и здесь

...