About testability
Due to the use of singletons and static classes MyViewModel isn't testable. Unit testing is about isolation. If you want to unit test some class (for example, MyViewModel) you need to be able to substitute its dependencies by test double (usually stub or mock). This ability comes only when you provide seams in your code. One of the best techniques used to provide seams is Dependency Injection. The best resource for learning DI is this book from Mark Seemann (Dependency Injection in .NET).
You can't easily substitute calls of static members. So if you use many static members then your design isn't perfect.
Of course, you can use unconstrained isolation framework such as Typemock Isolator, JustMock or Microsoft Fakes to fake static method calls but it costs money and it doesn't push you to better design. These frameworks are great for creating test harness for legacy code.
About design
- Constructor of MyViewModel is doing too much. Constructors should be simple.
- If the dependecy is null then constructor must throw ArgumentNullException but not silently log the error. Throwing an exception is a clear indication that your object isn't usable.
About testing framework
You can use any unit testing framework you like. Even MSTest, but personally I don't recommend it. NUnit and xUnit.net are MUCH better.
Further reading
- Mark Seeman - Dependency Injection in .NET
- Roy Osherove - The Art of Unit Testing (2nd Edition)
- Michael Feathers - Working Effectively with Legacy Code
- Gerard Meszaros - xUnit Test Patterns
Sample (using MvvmLight, NUnit and 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);
}
}