Я пишу тест, который ожидает получения события от объекта, который он вызывает. В частности, я обращаюсь к объекту, который подключается к машине AIX через SSH (используя проект Granados с открытым исходным кодом), затем отключаюсь, и я хочу убедиться, что получаю событие OnConnectionClosed, которое вызывается во время разъединения. Это звучит достаточно просто, и в прошлом я написал много таких тестов, но на этот раз происходит странное поведение, которое, я считаю, связано с многопоточностью.
По сути, вызываемый мной объект вызывает событие OnConnectionClosed в потоке, отличном от того, из которого я его вызываю. Я вижу, что когда я запускаю тест, выбирая «Debug Test» из пользовательского интерфейса, он проходит, но если я выбираю «Run Test», он терпит неудачу (даже если во время выполнения отладки не заданы точки останова). Я выполнил поиск в Google и нашел в этом посте , который, кажется, указывает на то, что по умолчанию хост MSTest работает в однопоточном режиме, но изменение конфигурации может заставить его работать в многопоточном режиме. Это звучало так, как будто это логически решило бы мою проблему, но, конечно, это не так.
Некоторые другие посты, с которыми я сталкивался, также заставляют меня думать, что MSTest просто не отслеживает фоновые потоки (поэтому вызванные ими события не «слышны»). Это также имело бы смысл, и, поскольку кажется, что оно работает в режиме отладки, и кажется, что исправление, приведенное выше, должно логически решить эту проблему, я не понимаю, почему он не работает. Вполне возможно, что я просто неправильно обращаюсь с потоками, хотя я ожидаю, что в режиме отладки это все равно будет проблемой, если бы это было так.
Кто-нибудь еще пытался что-то протестировать подобным образом? Если да, сталкивались ли вы с подобными проблемами? И если да, то как вы решили их?
Я вставил соответствующий код модульного теста ниже (я удалил информацию о соединении из соображений безопасности).
[TestClass]
public class SSHReaderTests
{
private bool received = false;
private delegate bool SimpleFunc();
[TestInitialize]
public void MyTestInitialize()
{
received = false;
}
[TestMethod]
public void Should_raise_OnReaderConnectionClosed_event_after_successful_connection_is_disconnected()
{
IReader reader = new SSHReader();
reader.OnReaderConnectionClosed += delegate
{
received = true;
};
reader.Connect("*****", "*****", "*****");
//Assert.IsTrue(reader.IsConnected);
reader.Disconnect();
//Assert.IsFalse(reader.IsConnected);
Assert.IsTrue(WaitUntilTrue(delegate {
return received; }, 30000, 1000));
}
private static bool WaitUntilTrue(SimpleFunc func, int timeoutInMillis, int timeBetweenChecksInMillis)
{
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
while(stopwatch.ElapsedMilliseconds < timeoutInMillis)
{
if (func())
return true;
Thread.Sleep(timeBetweenChecksInMillis);
}
return false;
}
}