Интеграционное тестирование ViewModel, который асинхронно вызывает службы WCF в приложении WPF MVVM - PullRequest
3 голосов
/ 24 августа 2010

Silverlight Toolkit содержит функциональность модульного тестирования, которая позволяет тестировать классы, такие как ViewModels, в приложении MVVM, которое асинхронно вызывает удаленные сервисы.

Я хотел бы иметь возможность выполнять свои интеграционные тесты ViewModel с фактическимиуслуги вместо насмешливых экземпляров.

Существует ли какая-либо поддержка асинхронного модульного / интеграционного тестирования для приложений WPF?

Обновление:

В конце дня мое решение объединилопредложения ктутника и алекса павена.Я написал крошечный вспомогательный класс, который добавляет немного синтаксического сахара:

public static class AsyncMethod
{
    public delegate void AsyncMethodCallback(AsyncMethodContext ctx);

    public static void Call(AsyncMethodCallback cb)
    {
        // create the sync object and make it available via TLS
        using (var syncObject = new AutoResetEvent(false))
        {
            // call the decorated method
            cb(new AsyncMethodContext(syncObject));
        }
    }
}

/// <summary>Asnc Method Callback Synchronization Context</summary>
public class AsyncMethodContext
{
    public AsyncMethodContext(EventWaitHandle syncObject)
    {
        this.syncObject = syncObject;
    }

    private readonly EventWaitHandle syncObject;

    /// <summary>
    /// Waits for completion.
    /// </summary>
    public void WaitForCompletion()
    {
        syncObject.WaitOne();
    }

    /// <summary>
    /// Signals the current operation as complete
    /// </summary>
    public void Complete()
    {
        syncObject.Set();
    }
}

Вот пример тестового примера в сочетании с использованием расширений Microsoft Rx:

[TestMethod]
public void TestGuestLogin()
{
    AsyncMethod.Call((ctx) =>
    {
        var vm = ServiceLocator.Get<LoginDialogViewModel>();

        // setup VM data
        vm.Username = "guest";
        vm.Password = "guest";
        vm.AutoLogin = false;
        GenericInfoEventArgs<LoginDialogViewModel.LoginRequestResult> loginResult = null;

        // pre-flight check
        Assert.IsTrue(vm.LoginCmd.CanExecute(null));

        // create Observable for the VM's LoginRequestComplete event
        var loginEvent = Observable.FromEvent<GenericInfoEventArgs<LoginDialogViewModel.LoginRequestResult>>(vm, "LoginRequestComplete").Do((e) =>
        {
            Debug.WriteLine(e.ToString());
        });

        // subscribe to it
        var loginEventSubscription = loginEvent.Subscribe((e) =>
        {
            loginResult = e.EventArgs;

            // test complete
            ctx.Complete();
        });

        // set things in motion
        using (loginEventSubscription)
        {
            vm.LoginCmd.Execute(null);
            ctx.WaitForCompletion();

            Assert.IsTrue(loginResult.Info.Success, "Login was not successful");
        }
    });
}

Ответы [ 2 ]

3 голосов
/ 25 августа 2010

Я долго охотился за этой функцией, но пока не повезло.

Не совсем чистое решение, но это работа для меня. Обычно я использовал ManualResetEvent, поэтому процесс тестирования не прерывался до тех пор, пока не будет выполнено асинхронное выполнение. Вот идея:

//set false for initial state
resetEvent = new ManualResetEvent(false);
//do the test
myObjec.MakeMeHappyAssync();
//just wait until its state set 
//when your call done
resetEvent.WaitOne();
//do assertion here

И где-то в вашем полном методе или методе ошибки вы просто вызываете

resetEvent.Set();

В любом случае, если вы нашли какую-либо новую информацию о функции, пожалуйста, сообщите мне

С наилучшими пожеланиями

1 голос
/ 26 августа 2010

Вы можете посмотреть на Reactive Extensions, которые теперь включены в .Net Framework 4, предполагая, что вы используете его; есть версии для 3.5 и Silverlight. Они допускают некоторое хорошее асинхронное кодирование, я использовал их в модульном тестировании ранее. См. здесь для статьи в блоге, обсуждающей это.

...