首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Caliburn.Micro单元测试

Caliburn.Micro单元测试
EN

Stack Overflow用户
提问于 2013-03-24 04:30:27
回答 1查看 4.2K关注 0票数 3

我正在用MVVM做我的第一步。

我使用Caliburn.Micro作为我的MVVM框架。

我有以下代码:

代码语言:javascript
复制
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的文档似乎缺少这些信息。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-03-25 18:55:48

好的,你可以通过IoC容器运行整个应用程序并引导整个过程,这样你就可以得到所有接口的实际具体实现。这样做的缺点是你将需要所有可用的东西(数据库,web服务等),如果你非常需要它运行,那么测试一个应用程序可能会更加困难(并且执行测试可能会慢得多,因为实际的工作正在完成)。如果你可以很容易地走这条路,那么一定要使用它。

或者,您可以通过使用mocking框架(如Moq ),使用mock或stub来模拟对象的行为/状态

使用Moq,您可以设置您的测试环境,以便您的接口和类由Mock<T> (模拟对象)表示,您可以为其指定行为。然后在ViewModels中对该行为进行测试

下面是在MainViewModel当前版本中使用Moq和NUnit的一组测试示例:

代码语言:javascript
复制
// 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");
    }
}

您可以看到如何测试状态和行为,我期望在调用诸如ChangeTitle之类的VM方法时有一个特定的VM状态,我也期望有一个行为(我希望Subscribe(X)在每次测试开始时至少在聚合器上调用一次)。

[SetUp]修饰的方法将在每次测试开始时被调用。有teardown和其他方法(包括设置整个测试夹具的方法,即每个夹具只运行一次)

这里的关键可能是,对于CM,您实际上不需要模拟事件聚合器中的任何行为,因为CM希望您为事件聚合器消息实现IHandle<T>。使这些subscriber方法成为接口实现意味着您的对象上已经有了公共方法,您可以调用这些公共方法来模拟事件聚合器调用。

例如,您可以使用

代码语言:javascript
复制
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

票数 5
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15591723

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档