首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >模仿界面没有意义吗?

模仿界面没有意义吗?
EN

Stack Overflow用户
提问于 2019-06-17 18:21:21
回答 1查看 58关注 0票数 1

我刚开始进行单元测试,感觉好像我错过了一些很重要的东西。我想在下面测试DoSomethingWithArray的结果:

代码语言:javascript
复制
class Traffic:ITraffic
{
    private HugeArray _hugeArray;
    public Traffic(HugeArray hugeArray)
    {
        _hugeArray = hugeArray;

    }

    public int DoSomethingWithArray()
    {
        var ret = 0;
        //Here some code that does something with big array and stores some integer values in ret
        return ret;
    }
}

class HugeArray
{
    //This is my custom data structure;
}

interface ITraffic
{
    int DoSomethingWithArray();
}

我正在使用Nunit,从我所读到的情况来看,模拟接口比模拟类更好。我的问题是,我想测试的是DosomethingWithArray在类流量中的具体功能,我很难概念化ITraffic如何适应这个接口。我在这里错过了什么?

这里的编辑是如何测试我的类的

代码语言:javascript
复制
[TestFixture]
public class TrafficTests
{
    private Traffic _traffic;
    private const int size = 1000000;
    private const int key = 1851925790;

    [OneTimeSetUp]
    public void Setup()
    {
        var hugeArray = new HugeArray(size);
        //Some Setups to create an edge case, not  relevant to my question
        hugeArray.AddValue(size - 1, Int.MaxValue);
        hugeArray.AddValue(size - 2, key);
        //This is the object I want to test, 
        _traffic = new Traffic(hugeArray);
    }

    [Test]
    public void DoSomethingWithArray_Test()
    {
        Assert.DoesNotThrow(() =>
                            {
                                var ret = _traffic.DoSomethingWithArray();
                                Assert.AreEqual(ret, 233398);
                            });
    }



} 

我的问题是:这种方法看起来正确吗?是否为测试创建了对象,还是应该模拟接口ITraffic?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-06-17 19:13:23

在您的示例中,您正在测试Traffic的公共方法。Traffic实现ITraffic并不重要。如果您从类中删除了: ITraffic,使它不再实现该接口,那么它根本不会改变您测试Traffic的方式。

你在测试Traffic。我们不会嘲笑我们正在测试的东西。我们嘲笑我们没有测试的东西。

假设我有一个类来验证一个地址:

代码语言:javascript
复制
public class AddressValidator
{
    public ValidationResult ValidateAddress(Address address)
    {
        var result = new ValidationResult();

        if(string.IsNullOrEmpty(address.Line1))
            result.AddError("Address line 1 is empty.");
        if(string.IsNullOrEmpty(address.City))
            result.AddError("The city is empty.");

        // more validations

        return result;
    }
}

这个类是否实现一个接口并不重要。如果我要测试这个类,就没有什么好模仿的了。

假设我意识到我还需要验证邮政编码,但为了做到这一点,我可能需要查询一些外部数据,以查看城市是否与邮政编码匹配。也许不同国家的情况不同。所以我编写了一个新的接口并将它注入到这个类中:

代码语言:javascript
复制
public interface IPostalCodeValidator
{
    ValidationResult ValidatePostalCode(Address address);
}

public class AddressValidator
{
    private readonly IPostalCodeValidator _postalCodeValidator;

    public AddressValidator(IPostalCodeValidator postalCodeValidator)
    {
        _postalCodeValidator = postalCodeValidator;
    }

    public ValidationResult ValidateAddress(Address address)
    {
        var result = new ValidationResult();

        if (string.IsNullOrEmpty(address.Line1))
            result.AddError("Address line 1 is empty.");
        if (string.IsNullOrEmpty(address.City))
            result.AddError("The city is empty.");

        var postalCodeValidation = _postalCodeValidator.ValidatePostalCode(address);
        if (postalCodeValidation.HasErrors)
            result.AddErrors(postalCodeValidation.Errors);

        return result;
    }
}

邮政编码验证非常复杂,因此它将在自己的类中使用自己的测试。当我们测试AddressValidator时,我们不想测试邮政编码验证器。我们只想单独测试这个类,然后单独测试另一个类。在AddressValidator中,我们希望确保调用_postalCodeValidator.ValidatePostalCode,如果它返回错误,则将它们添加到验证结果中。

我们没有在这里测试IPostalCodeValidator (或它的实现),所以我们模拟它。例如,使用莫克

代码语言:javascript
复制
public void AddressValidator_adds_postal_code_errors()
{
    var postalCodeError = new ValidationResult();
    postalCodeError.AddError("Bad!");
    postalCodeError.AddError("Worse!");

    var postalCodeValidatorMock = new Mock<IPostalCodeValidator>();
    postalCodeValidatorMock.Setup(x => x.ValidatePostalCode(It.IsAny<Address>()))
        .Returns(postalCodeError);

    var subject = new AddressValidator(postalCodeValidatorMock.Object);
    var result = subject.ValidateAddress(new Address());

    Assert.IsTrue(result.Errors.Contains("Bad!"));
    Assert.IsTrue(result.Errors.Contains("Worse!"));
}

我们实际上并不是在验证邮政编码。我们只是说,为了测试,邮政编码验证器总是会返回这两个错误。然后,我们将确保AddressValidator调用它,并按照我们的预期对这些错误进行操作。

这基本上就是模仿的意思。这是一个假的实现,做一些简单的事情,比如罐头响应,这样我们就可以确保按照我们期望的方式来处理这个罐头响应。如果AddressValidator正确地处理结果,那么它就能正常工作。就这样办。

为了确保真正的邮政编码验证器返回正确的结果,我们可以为该类编写测试。这样,每个类都会做一些简单的事情,并进行测试,以确保它正确地完成它的任务。当我们把它们放在一起的时候,整件事就更有可能成功了。如果我们破坏了IPostalCodeValidator的实现,那么该类的测试将失败,但是AddressValidator的测试仍然会通过。这样我们就可以快速了解哪一部分已经失效,因为它们都是隔离测试的,所以我们不需要运行和调试大量的代码来找出问题所在。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/56636861

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档