В настоящее время я работаю над некоторым программным обеспечением на основе .Net (.Net Framework 3.5 SP1), которое интегрируется с HP Quality Center 10.0 через его API-интерфейс COM-клиента (часто называемый TDApiOle80 или TDApiOle80.TDConnection).
Мы используем XUnit 1.6.1.1521 и Gallio 3.1.397.0 (вызываются из файла msbuild)
Мы выполняем процесс:
- Создание соединения
- Выполнение теста
- Закрытие соединения
- Удаление
- Форсирование GC.Collection () / GC.AwaitingPendingFinalizers ()
Для каждой интеграцииtest - и каждый интеграционный тест выполняется с тайм-аутом, настроенным в его Fact.
Проблема, с которой мы столкнулись, заключается в том, что он появляется после нескольких тестов (скажем, около 10 или около того), когда Quality Center блокируется бесконечно при вызове - ивесь Gallio зависает и больше не отвечает.
Изначально мы обнаружили, что xunit.net применяет только тайм-аут к коду внутри факта - так что он будет ждать неопределенно долгоr конструктор или избавьтесь от методов для завершения - поэтому мы переместили эту логику в тело тестов только для подтверждения ... но это не решило проблему (все еще будет зависать после выполнения определенного количества тестов).
То же самое происходит при использовании TestDriven.Net - можно запустить 1 или несколько тестов в интерактивном режиме, но более 10 тестов и весь цикл останавливается - и наш единственный выбор - завершить процесс ProcessInvocation86.exe, используемый TD.Net.
Есть ли у кого-нибудь какие-либо советы или подсказки о том, как остановить это все вместе, или, по крайней мере, изолировать мои интеграционные тесты от подобных проблем - чтобы тесты, в которых API QC блокировался на неопределенный срок,тест завершится неудачно с тайм-аутом и позволит Gallio перейти к следующему тесту.
Обновление
Подсказка к использованию потока STA помогла немного продвинуть проблему вперед.- с помощью специального атрибута XUnit.Net мы теперь запускаем тест в своем собственном потоке STA.Это предотвратило полную блокировку Gallio / TestDriven.Net, поэтому мы можем включить запуск интеграционных тестов на нашем сервере сборки hudson.
public class StaThreadFactAttribute : FactAttribute
{
const int DefaultTime = 30000; // 30 seconds
public StaThreadFactAttribute()
{
Timeout = DefaultTime;
}
protected override System.Collections.Generic.IEnumerable<Xunit.Sdk.ITestCommand> EnumerateTestCommands(Xunit.Sdk.IMethodInfo method)
{
int timeout = Timeout;
Timeout = 0;
var commands = base.EnumerateTestCommands(method).ToList();
Timeout = timeout;
return commands.Select(command => new StaThreadTimeoutCommand(command, Timeout, method)).Cast<ITestCommand>();
}
}
public class StaThreadTimeoutCommand : DelegatingTestCommand
{
readonly int _timeout;
readonly IMethodInfo _testMethod;
public StaThreadTimeoutCommand(ITestCommand innerComand, int timeout, IMethodInfo testMethod)
: base(innerComand)
{
_timeout = timeout;
_testMethod = testMethod;
}
public override MethodResult Execute(object testClass)
{
MethodResult result = null;
ThreadStart work = delegate
{
try
{
result = InnerCommand.Execute(testClass);
var disposable = testClass as IDisposable;
if (disposable != null) disposable.Dispose();
}
catch (Exception ex)
{
result = new FailedResult(_testMethod, ex, this.DisplayName);
}
};
var thread = new Thread(work);
thread.SetApartmentState(ApartmentState.STA); //Set the thread to STA
thread.Start();
if (!thread.Join(_timeout))
{
return new FailedResult(_testMethod, new Xunit.Sdk.TimeoutException((long)_timeout), base.DisplayName);
}
return result;
}
}
Вместо этого мы теперь видим вывод, подобный этому, при запуске тестов с TestDriven.Net - случайный запуск одного и того же пакета несколько раз приведет либо к тому, что все тесты пройдут, либо, как правило, только один или два теста не пройдены.А после первого сбоя второй сбой приводит к проблеме «Ошибка при выгрузке домена приложения».
Тест «IntegrationTests.Execute_Test1» не выполнен: превышено время выполнения теста: 30000 мс
ТестОшибка «T: IntegrationTests.Execute_Test2»: ошибка при выгрузке домена приложения.(Исключение из HRESULT: 0x80131015) System.CannotUnloadAppDomainException: ошибка при выгрузке домена приложения.(Исключение из HRESULT: 0x80131015) в System.AppDomain.Unload (домен AppDomain) в Xunit.ExecutorWrapper.Dispose () в Xunit.Runner.TdNet.TdNetRunner.TestDriven.Framework.ITestRunner.RunMember, слушатель-сборщик, член сборочной единицы ITestListener) в TestDriven.TestRunner.AdaptorTestRunner.Run (ITestListener testListener, ITraceListener traceListener, String assemblyPath, String testPath) в TestDriven.TestRunner.ThreadTestRunner.Runner.Run ()
4 пройдено, прошло 2, получено 2, пройдено 2, принято 250,42 секунды (xunit).
Мне еще предстоит выяснить, почему API Quality Center зависает на неопределенное время в произвольном порядке - это будет рассмотрено в ближайшее время.
Обновление 27/ 07/2010
Я наконец установил причину зависания - вот проблемный код:
connection = new TDConnection();
connection.InitConnectionEx(credentials.Host);
connection.Login(credentials.User, credentials.Password);
connection.Connect(credentials.Domain, credentials.Project);
connection.ConnectProjectEx(credentials.Domain, credentials.Project, credentials.User, credentials.Password);
Похоже, что вызов Connect, сопровождаемый ConnectProjectEx, имеет шансблокировка (но это недетерминировано).Удаление избыточных вызовов для подключения значительно повысило стабильность тестирования - правильный код подключения:
connection = new TDConnection();
connection.InitConnectionEx(credentials.Host);
connection.ConnectProjectEx(credentials.Domain, credentials.Project, credentials.User, credentials.Password);
Унаследовав кодовую базу, я не очень задумывался о коде соединения.
Одна вещь, которую мне еще предстоит выяснить, - это то, почему даже с указанным выше кодом таймаута Thread.Join (timeout) никогдавозвращается.Вы можете присоединить отладчик, и он просто показывает, что тестовый поток находится в операции соединения / ожидания.Возможно, что-то делать с выполнением в потоке STA?