模拟视图模型以进行最小起订量进行单元测试

本文关键字:单元测试 视图 模拟 模型 | 更新日期: 2024-11-07 05:28:57

单元测试的新手。我有一个 WPF 客户端应用程序通过 basicHttpbinding 挂接到 WCF 服务。一切都很好。我在我的视图模型中使用简单的构造函数依赖注入,传入一个IServiceChannel然后我称之为服务方法,例如:

IMyserviceChannel = MyService;
public MyViewModel(IMyServiceChannel myService)
{
   this.MyService = myService;  
}
Private void GetPerson()
{
  var selectedPerson = MyService.GetSelectedPerson();
}

然后,我在客户端应用程序中添加了一个 MS Test 项目,我正在尝试使用 Moq 来模拟我的服务:

  [TestMethod]
    public void GetArticleBody_Test_Valid()
    {
        // Create channel mock
        Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>(MockBehavior.Strict);    
        // setup the mock to expect the Reverse method to be called
        channelMock.Setup(c => c.GetArticleBody(1010000008)).Returns("110,956 bo/d, 1.42 Bcfg/d and 4,900 bc/d. ");
        // create string helper and invoke the Reverse method
        ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
        string result = channelMock.GetArticleBody(1010000008);
        //Assert.AreEqual("cba", result);
        //verify that the method was called on the mock
        channelMock.Verify(c => c.GetArticleBody(1010000008), Times.Once());
    }

测试失败,此处的方法调用System.NullReferenceException. Object reference not set to an instance of an object.

 string result = articleDataGridViewModel.IsesService.GetArticleBody(1010000008);

所以我在徘徊,这是否是最好的方法,或者我是否更好地以某种方式嘲笑适用于测试的视图模型的孤立部分?

模拟视图模型以进行最小起订量进行单元测试

抛出NullReferenceException是因为您使用MockBehavior.Strict 。文档说:

导致此模拟始终为没有相应设置的调用引发异常。

也许ArticleDataGridViewModel的构造函数调用您尚未设置的其他服务方法。另一个问题是,您直接调用模拟方法。相反,您应该调用视图模型的方法,该方法将调用此方法。

[TestMethod]
public void GetArticleBody_Test_Valid()
{
    // Create channel mock
    Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>();    
    // setup the mock to expect the Reverse method to be called
    channelMock.Setup(c => c.GetArticleBody(1010000008)).Returns("110,956 bo/d, 1.42 Bcfg/d and 4,900 bc/d. ");
    // create string helper and invoke the Reverse method
    ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
    string result = articleDataGridViewModel.MethodThatCallsService();
    //Assert.AreEqual("cba", result);
    //verify that the method was called on the mock
    channelMock.Verify(c => c.GetArticleBody(1010000008), Times.Once());
}

除此之外,我认为你的方法没有问题。也许视图模型违反了单一责任原则,并且做得比它应该做的更多,但根据你的代码示例很难说出来。

编辑:这是一个完整的示例,说明如何测试这样的东西:

public interface IMyService
{
    int GetData();
}
public class MyViewModel
{
    private readonly IMyService myService;
    public MyViewModel(IMyService myService)
    {
        if (myService == null)
        {
            throw new ArgumentNullException("myService");
        }
        this.myService = myService;
    }
    public string ShowSomething()
    {
        return "Just a test " + this.myService.GetData();
    }
}
class TestClass
{
    [TestMethod]
    public void TestMethod()
    {
        var serviceMock = new Mock<IMyService>();
        var objectUnderTest = new MyViewModel(serviceMock.Object);
        serviceMock.Setup(x => x.GetData()).Returns(42);
        var result = objectUnderTest.ShowSomething();
        Assert.AreEqual("Just a test 42", result);
        serviceMock.Verify(c => c.GetData(), Times.Once());
    }
}

无法访问您的视图模型,我们能为您提供的帮助就只有这么多。

但是,此代码:

Mock<IIsesServiceChannel> channelMock = new Mock<IIsesServiceChannel>(MockBehavior.Strict);
...
ArticleDataGridViewModel articleDataGridViewModel = new ArticleDataGridViewModel(channelMock.Object);
...
string result = articleDataGridViewModel.IsesService.GetArticleBody(1010000008);

不设置您的 IsesService。如果未在构造函数中设置,则意味着 IsesService 是一个空引用。不能对 null 对象调用方法。

考虑在

更高的抽象级别上模拟出来,然后是你与你使用的工具的紧密耦合。

也许您的视图模型应该依赖于服务,而不是您使用的工具(即IIsesServiceChannel)的细节。

下面是一个示例:

构建可测试的业务层逻辑