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