Moq - 使用可空参数进行方法评估会抛出null异常

时间:2017-01-23 23:24:52

标签: c# unit-testing moq

我知道我可以新建一个对象并将其传入但是我正在尝试匹配语法和模式,因为该值实际上从未使用过。

实施

public interface IDemoProvider
{
    string GetStringById(int? id);
}

public interface IDemoService
{
    bool Validate(ServiceRequest request);
}

public class ServiceRequest
{
    public string foo { get; set; }
    public int? bar { get; set; }
}

public class SomeDemoProvider : IDemoProvider
{
    public virtual string GetStringById(int? id)
    {
        if (id != null)
            return "success";
        else
            return "else";
    }
}

public class BaseDemoService : IDemoService
{
    public IDemoProvider Provider { get; set; }

    public virtual bool Validate(ServiceRequest request)
    {
        if (request.bar == null)
            return false;

        return true;
    }
}

public class SomeDemoService : BaseDemoService
{
    public SomeDemoService(IDemoProvider provider)
    {
        Provider = provider;
    }

    public virtual string Post(ServiceRequest request)
    {
        if (!Validate(request))
            throw new Exception("Invalid Request");
        return Provider.GetStringById(request.bar);
    }
}

测试代码:

[TestFixture]
public class ProgramTests
{
    [Test]
    public void SomeDemoServiceTest()
    {
        var mockProvider = new Mock<IDemoProvider>();
        mockProvider.Setup(p => p.GetStringById(It.IsAny<int?>())).Returns(() => "success");

        object[] args = { mockProvider.Object };

        var mockService = new Mock<SomeDemoService>(args) {CallBase = true};
        mockService.Setup(s => s.Validate(It.IsAny<ServiceRequest>())).Returns(true);

        string result = mockService.Object.Post(It.IsAny<ServiceRequest>());

        Assert.AreEqual("success", result);
    }
}

问题

这导致NullReferenceException有意义,因为它正在尝试解析request.Id运行时在请求级别为null。

但是,如果我用null替换参数,它可以正常工作:

return Provider.GetStringById(null);

我的问题是,在评估表达式之前是否有某种方法可以让拦截器识别它应该只返回值而不是尝试计算表达式。

我可以模拟出请求对象的其余部分,但它似乎很愚蠢,因为根据测试从未使用过这些值。这里真正的问题是我是否应该以不同的方式编写代码或测试以避免这种情况,或者我是否通过简单的解决方法使问题复杂化。

2 个答案:

答案 0 :(得分:0)

你测试错了。

如果您正在尝试使用测试方法,那么这一行......

string result = mockService.Object.Post(It.IsAny<ServiceRequest>());

使用不当。您可以使用It.IsAny<ServiceRequest>()作为设置的一部分。对于您尝试使用它的方式,它将导致null方法中的Validate

request.bar == null

因为It.IsAny表达式实际上没有将任何内容传递给方法。

了解如何通过Moq Quickstart使用Moq,以便更好地了解测试时如何使用它。

将测试重写为

public void SomeDemoServiceTest() {
    //Arrange
    var mockProvider = new Mock<IDemoProvider>();
    mockProvider.Setup(p => p.GetStringById(It.IsAny<int?>())).Returns(() => "success");

    var mockService = new Mock<SomeDemoService>(mockProvider.Object) { CallBase = true };
    mockService.Setup(s => s.Validate(It.IsAny<ServiceRequest>())).Returns(true);

    var request = new ServiceRequest();

    //Act
    var result = mockService.Object.Post(request);

    //Assert
    Assert.AreEqual("success", result);
}

测试应该通过。

答案 1 :(得分:-2)

请检查您的request.SubProperty是否为null可能是对象引用为空的原因

{{1}}