在MVVMLight中使用Messaging编写单元测试用例需要帮助

3

我对编写单元测试案例完全陌生。我正在使用MVVMLigh与WPF。是否需要使用某些第三方测试框架或者.Net单元测试框架就足够了?还有如何在单元测试案例中处理静态类?在这种情况下是AppMessages类。

能否有人指导我如何为以下代码编写单元测试案例:

public MyViewModel(Participant participant)
{    
    if (participant != null)
    {
        this.ParentModel = parentModel;
        OkCommand = new RelayCommand(() => OkCommandExecute());
        CalculateAmountCommand = new RelayCommand(() => CalculateAmount());        
    }
    else
    {
        ExceptionLogger.Instance.LogException(Constants.ErrorMessages.FinancialLineCanNotBeNull, "FinancialLineViewModel");
        AppMessages.DisplayDialogMessage.Send(Constants.ErrorMessages.FinancialLineCanNotBeNull, MessageBoxButton.OK, Constants.DefaultCaption, null);
    }
}

public static class AppMessages
{
    enum AppMessageTypes
    {
        FinancialLineViewDisplay,
        FinancialLineViewClose,
        DisplayDialogMessage
    }

    public static class DisplayDialogMessage
    {
        public static void Send(string message, MessageBoxButton button, string caption, System.Action<MessageBoxResult> action)
        {
            DialogMessage dialogMessage = new DialogMessage(message, action)
            {
                Button = button,
                Caption = caption
            };

            Messenger.Default.Send(dialogMessage, AppMessageTypes.DisplayDialogMessage);
        }

        public static void Register(object recipient, System.Action<DialogMessage> action)
        {
            Messenger.Default.Register<DialogMessage>(recipient, AppMessageTypes.DisplayDialogMessage, action);
        }
    }
}

public class ExceptionLogger
{
    private static ExceptionLogger _logger;
    private static object _syncRoot = new object();

    public static ExceptionLogger Instance
    {
        get
        {
            if (_logger == null)
            {
                lock (_syncRoot)
                {
                    if (_logger == null)
                    {
                        _logger = new ExceptionLogger();
                    }
                }
            }

            return _logger;
        }
    }

    public void LogException(Exception exception, string additionalDetails)
    {
        LogException(exception.Message, additionalDetails);
    }

    public void LogException(string exceptionMessage, string additionalDetails)
    {
        MessageBox.Show(exceptionMessage);
    }
}

有关此事,您有什么建议吗? - Mahesh
1个回答

5

关于可测试性

由于使用了单例和静态类,MyViewModel不具备可测试性。单元测试是关于隔离的。如果要对某个类(比如MyViewModel)进行单元测试,则需要能够通过测试替身(通常是存根或模拟)来替换其依赖项。只有在您的代码中提供缝隙时才能做到这一点。最好用来提供缝隙的技术之一是依赖注入。学习DI的最佳资源是Mark Seemann的这本书(.NET中的依赖注入)

您无法轻松地替换静态成员的调用。因此,如果使用了许多静态成员,则设计不完美。

当然,您可以使用无约束的隔离框架,例如Typemock Isolator、JustMock或Microsoft Fakes来伪造静态方法调用,但这需要花费金钱,而且不会促使您更好的设计。这些框架非常适合为遗留代码创建测试框架。

关于设计

  1. MyViewModel的构造函数做了太多事情。 构造函数应该简单
  2. 如果依赖关系为null,则构造函数必须抛出ArgumentNullException,而不是默默记录错误。抛出异常清楚地表明您的对象无法使用。

关于测试框架

您可以使用任何喜欢的单元测试框架。即使是MSTest,但我个人不推荐它。 NUnit和xUnit.net要好得多。

进一步阅读

  1. Mark Seeman- .NET中的依赖注入
  2. Roy Osherove-单元测试的艺术(第二版)
  3. Michael Feathers-有效地使用遗留代码工作
  4. Gerard Meszaros-xUnit测试模式

示例(使用MvvmLight、NUnit和NSubstitute)

public class ViewModel : ViewModelBase
{
    public ViewModel(IMessenger messenger)
    {
        if (messenger == null)
            throw new ArgumentNullException("messenger");

        MessengerInstance = messenger;
    }

    public void SendMessage()
    {
        MessengerInstance.Send(Messages.SomeMessage);
    }
}

public static class Messages
{
    public static readonly string SomeMessage = "SomeMessage";
}

public class ViewModelTests
{
    private static ViewModel CreateViewModel(IMessenger messenger = null)
    {
        return new ViewModel(messenger ?? Substitute.For<IMessenger>());
    }

    [Test]
    public void Constructor_WithNullMessenger_ExpectedThrowsArgumentNullException()
    {
        var exception = Assert.Throws<ArgumentNullException>(() => new ViewModel(null));
        Assert.AreEqual("messenger", exception.ParamName);
    }

    [Test]
    public void SendMessage_ExpectedSendSomeMessageThroughMessenger()
    {
        // Arrange
        var messengerMock = Substitute.For<IMessenger>();
        var viewModel = CreateViewModel(messengerMock);

        // Act
        viewModel.SendMessage();

        // Assert
        messengerMock.Received().Send(Messages.SomeMessage);
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接