Модульное тестирование событий COM? - PullRequest
7 голосов
/ 14 декабря 2011

У нас есть самодельный компонент COM, написанный на C ++. Теперь мы хотим протестировать его функции и события в C # Test Project. Функциональные тесты довольно просты. Однако события никогда не инициируются.

MyLib.MyClass m = new MyLib.MyClass();
Assert.IsTrue(m.doStuff()); // Works

// This does not work. OnMyEvent is never called!
m.MyEvent += new MyLib.IMyClassEvents_MyEventHandler(OnMyEvent);
m.triggerEvent();

Я нашел это в Google и прочитал о похожих проблемах здесь, в StackOverflow. Я перепробовал все предложенные методы, но не могу заставить его работать!

До сих пор я пытался запустить свой тест с активным диспетчером , но безуспешно. Я также пробовал вручную перекачивать сообщения в основной ветке, используя Dispatcher.PushFrame(). Ничего такого. Мои события никогда не сработают. Я создал простой проект WinForms и проверил, что мои события работают в обычной настройке. Следовательно, эта проблема относится только к юнит-тестам.

В: Как выполнить обычный модульный тест C #, который может успешно запускать активные обработчики событий?

У кого-то должен быть рабочий образец! Пожалуйста, помогите.

1 Ответ

1 голос
/ 18 июля 2012

Если ваш COM-объект является объектом STA, вам, вероятно, нужно запустить цикл сообщений, чтобы его события сработали.

Вы можете использовать небольшую оболочку вокруг объекта Application и Formсделать это.Вот небольшой пример, который я написал за несколько минут.

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

При таком подходе тестовый класс будет выглядеть примерно так:

[TestMethod]
public void Test()
{
    MessageLoopTestRunner.Run(

        // the logic of the test that should run on top of a message loop
        runner =>
        {
            var myObject = new ComObject();

            myObject.MyEvent += (source, args) =>
            {
                Assert.AreEqual(5, args.Value);

                // tell the runner we don't need the message loop anymore
                runner.Finish();
            };

            myObject.TriggerEvent(5);
        },

        // timeout to terminate message loop if test doesn't finish
        TimeSpan.FromSeconds(3));
}

А код для MessageLoopTestRunner будет что-то вродевот так:

public interface IMessageLoopTestRunner
{
    void Finish();
}

public class MessageLoopTestRunner : Form, IMessageLoopTestRunner
{
    public static void Run(Action<IMessageLoopTestRunner> test, TimeSpan timeout)
    {
        Application.Run(new MessageLoopTestRunner(test, timeout));
    }

    private readonly Action<IMessageLoopTestRunner> test;
    private readonly Timer timeoutTimer;

    private MessageLoopTestRunner(Action<IMessageLoopTestRunner> test, TimeSpan timeout)
    {
        this.test = test;
        this.timeoutTimer = new Timer
        {
            Interval = (int)timeout.TotalMilliseconds, 
            Enabled = true
        };

        this.timeoutTimer.Tick += delegate { this.Timeout(); };
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        // queue execution of the test on the message queue
        this.BeginInvoke(new MethodInvoker(() => this.test(this)));
    }

    private void Timeout()
    {
        this.Finish();
        throw new Exception("Test timed out.");
    }

    public void Finish()
    {
        this.timeoutTimer.Dispose();
        this.Close();
    }
}

Это помогает?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...