Как написать модульный тест MSTest, который прослушивает событие, вызываемое из другого потока? - PullRequest
0 голосов
/ 20 октября 2008

Я пишу тест, который ожидает получения события от объекта, который он вызывает. В частности, я обращаюсь к объекту, который подключается к машине 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;
    }
}

Ответы [ 2 ]

2 голосов
/ 21 октября 2008

Используйте классы WaitHandle в пространстве имен System.Threading. Либо AutoResetEvent, либо ManualResetEvent. Разница между ними заключается в том, что AutoResetEvent позволяет одному потоку продолжаться каждый раз, когда он установлен, а ManualResetEvent освобождает все ожидающие потоки в наборе.

Причина, по которой ваш пример не работает, связана с оптимизацией компилятора. Код на самом деле не скомпилирован с тем, что вы думаете на первый взгляд. Скорее всего, компилятор сделает что-то вроде размещения локальной переменной в регистре и никогда не извлечет ее во время проверки. Вы можете избежать такого рода вещей с помощью ключевого слова volatile, но я настоятельно рекомендую ознакомиться с многопоточностью и параллелизмом для получения более подробной информации. Блог Джо Даффи по адресу http://www.bluebytesoftware.com - отличный ресурс для начала, и я настоятельно рекомендую его книгу по параллелизму в Windows, которая скоро выйдет.

0 голосов
/ 21 октября 2008

Не совсем то, о чем вы спрашиваете, но вы можете найти некоторые работоспособные решения или хотя бы идеи, проверив проект MS Research под названием CHESS . Это для многопоточного параллельного тестирования в .net.

...