我对单元测试用例写作完全陌生。我在WPF中使用MVVMLigh。是否有必要使用一些第三方测试框架或.Net Unit测试框架呢?另外如何在单元测试用例中处理静态类?在本例中为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);
}
}
答案 0 :(得分:5)
关于可测试性
由于使用单例和静态类,MyViewModel无法测试。单元测试是关于隔离的。如果要对某个类(例如,MyViewModel)进行单元测试,则需要能够通过test double(通常是存根或模拟)替换其依赖项。只有在代码中提供接缝时才会出现此功能。用于提供接缝的最佳技术之一是依赖注入。学习DI的最佳资源来自Mark Seemann (Dependency Injection in .NET)。
您无法轻易替换静态成员的调用。因此,如果您使用许多静态成员,那么您的设计并不完美。
当然,您可以使用无约束隔离框架(如Typemock Isolator,JustMock或Microsoft Fakes)伪造静态方法调用,但这需要花钱,并且不会促使您更好地设计。这些框架非常适合为遗留代码创建测试工具。
关于设计
关于测试框架
您可以使用任何您喜欢的单元测试框架。即使是MSTest,但我个人并不推荐它。 NUnit和xUnit.net要好得多。
进一步阅读
示例(使用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);
}
}