3

私はMVVMで最初のステップを実行しています。

MVVMフレームワークとしてCaliburn.Microを使用しています。

私は次のコードを持っています:

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Globalization;

using Caliburn.Micro;

namespace MY_PROJECT.ViewModels
{   
    [Export(typeof(MainViewModel))]
    public class MainViewModel : Screen
    {     
        private readonly IWindowManager _windowManager = null;

        private readonly IEventAggregator _events;

        private string _title = string.Empty;          

        private WindowState _windowState = WindowState.Normal;

        public string Title
        {
            get
            {
               return _title;
            }
            set
            {
               _title = value;
               NotifyOfPropertyChange(() => Title);
            }
        }

        public WindowState WindowState
        {
            get
            {
                return _windowState;
            }
            set
            {
                _windowState = value;
                NotifyOfPropertyChange(() => WindowState);
            }
        }

        public void ChangeTittle(string title)
        {
             Title = title;
        }

        public void ToggleWindowState()
        {
             WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
        }

        [ImportingConstructor]
        public MainViewModel(IWindowManager windowManager, IEventAggregator events)
        {
            _windowManager = windowManager;
            _events = events;
            _events.Subscribe(this);
        }
  }

次に、ビューモデルをテストするための簡単な単体テストをいくつか作成します。

それを行う方法の提案はありますか?

Caliburn.Microのドキュメントには、この情報が欠落しているようです。

4

1 に答える 1

5

IoC コンテナーを介してアプリ全体を実行し、すべてをブートストラップするだけで、すべてのインターフェイスの実際の具体的な実装を取得できます。これの欠点は、利用可能なすべてのもの (データベース、Web サービスなど) が必要になり、アプリケーションをすべて実行する必要がある場合は、アプリケーションのテストがより困難になる可能性があることです (実際の作業が行われているため、テストの実行がはるかに遅くなる可能性があります)。終わり)。このルートを簡単に実行できる場合は、ぜひ使用してください。

または、Moq などのモック フレームワークを使用して、モックまたはスタブを使用してオブジェクトの動作/状態をモックすることもできます。

Moq を使用するとMock<T>、動作を指定する (モック オブジェクト) によってインターフェイスとクラスが表されるように、テスト環境をセットアップします。次に、その動作に対してテストしますViewModels

MainViewModel現在の化身でMoq と NUnit を使用した一連のテストの例を次に示します。

// Decorate with test fixture attribute so NUnit knows it's a test
[TestFixture]
class MainViewModelTests
{           
    // The interfaces/instances you will need to test with - this is your test subject
    MainViewModel _mainVM;

    // You can mock the other interfaces:
    Mock<IWindowManager> _windowManager;
    Mock<IEventAggregator> _eventAggregator; 

    // Setup method will run at the start of each test
    [SetUp]
    public void Setup() 
    {
        // Mock the window manager
        _windowManager = new Mock<IWindowManager>();               

        // Mock the event aggregator
        _windowManager = new Mock<IEventAggregator>(); 

        // Create the main VM injecting the mocked interfaces
        // Mocking interfaces is always good as there is a lot of freedom
        // Use mock.Object to get hold of the object, the mock is just a proxy that decorates the original object
        _mainVM = new MainViewModel(_windowManager.Object, _eventAggregator.Object);
    }

    // Create a test to make sure the VM subscribes to the aggregator (a GOOD test, I forget to do this a LOT and this test gives me a slap in the face)
    [Test]
    public void Test_SubscribedToEventAggregator()
    {
        // Test to make sure subscribe was called on the event aggregator at least once
        _eventAggregator.Verify(x => x.Subscribe(_mainVM));
    }

    // Check that window state toggles ok when it's called
    [Test]
    public void Test_WindowStateTogglesCorrectly()
    {
        // Run the aggregator test at the start of each test (this will run as a 'child' test)
        Test_SubscribedToEventAggregator();

        // Check the default state of the window is Normal
        Assert.True(_mainVM.WindowState == WindowState.Normal);

        // Toggle it
        _mainVM.ToggleWindowState();

        // Check it's maximised
        Assert.True(_mainVM.WindowState == WindowState.Maximised);

        // Check toggle again for normal
        _mainVM.ToggleWindowState();

        Assert.True(_mainVM.WindowState == WindowState.Normal);
    }

    // Test the title changes correctly when the method is called
    [Test]
    public void Test_WindowTitleChanges()
    {
         Test_SubscribedToEventAggregator();

         _mainVM.ChangeTitle("test title");
         Assert.True(_mainVM.Title == "test title");
    }
}

状態と動作をテストする方法を確認できます。VM メソッドが呼び出されたときに特定の VM 状態ChangeTitleが予想され、動作も予想されました (Subscribe(X)各テストの開始時にアグリゲーターで少なくとも 1 回呼び出されると予想していました)。 .

で装飾されたメソッド[SetUp]は、各テストの開始時に呼び出されます。分解およびその他の方法があります (テスト フィクスチャ全体をセットアップする方法、つまり、フィクスチャごとに 1 回だけ実行する方法を含む)。

ここで重要なことは、CM ではIHandle<T>イベント アグリゲーターのメッセージを実装することを想定しているため、イベント アグリゲーターの動作を実際にモックする必要がないということです。これらのサブスクライバー メソッドをインターフェイス実装にするということは、イベント アグリゲーター呼び出しをシミュレートするために呼び出すことができるパブリック メソッドがオブジェクトに既にあることを意味します。

たとえば、使用できます

public class MainViewModel : IHandle<someEventMessageArgument> // (this is your subscriber interface)
{ 
    // (and this is the corresponding method)
    public void Handle(someEventMessageArgument message) 
    { 
        // do something useful maybe change object state or call some methods
    }
}

// Test the method - you don't need to mock any event aggregator behaviour since you have tested that the VM was subscribed to the aggregator. (OK CM might be broken but that's Robs problem :))
[Test]
Test_SomeEventDoesWhatYouAreExpecting()
{
    _mainVM.Handle(someEventMessageArgument);

    // Assert that what was supposed to happen happened...
    Assert.True(SomethingHappened);
}

ここで Moq クイックスタートを確認してください。

http://code.google.com/p/moq/wiki/QuickStart

于 2013-03-25T10:55:47.747 に答える