【问题标题】:Stub protected List in base class for unit-test用于单元测试的基类中的存根受保护列表
【发布时间】:2013-08-07 15:30:52
【问题描述】:

我想测试一个方法是否将一个对象添加到基类的列表中。

我的问题是该列表受到保护,因此我无法在我的测试安排中填充它。因此列表为空,我的方法无法在特定索引处添加对象。

如何制作存根列表并使用它而不是真正的基类列表而不将其公开?

我正在使用 NUnit 和 Moq。

这是一些模仿我的问题的代码:

public class Person
{
    public string Name { get; set; }
    readonly List<PhoneNumber> _numbers = new List<PhoneNumber>();

    public void AddNumber(PhoneNumber phoneNumber)
    {
        _numbers.Add(phoneNumber);
    }
}

public class PhoneNumber
{
    public int Number { get; set; }
}

public class BaseClass
{
    protected List<Person> Persons = new List<Person>();
}

public class DerivedClass : BaseClass
{
    public void AddNumberToPersons(int index, PhoneNumber phoneNumber)
    {
        Persons[index].AddNumber(phoneNumber); // <-- Need to test if 
                                               // this gets called without errors
    }
}

[Test]
public void AddNumberToPersons_WhenAddingNumberToPersons_NumberGetsAddedToList()
{
    // I think I need to use a stub list or else the list is empty 
    // and index is out of range.

    // Assert that number is added to the list.
}

【问题讨论】:

  • 电话号码是否添加到人身上真的很重要吗?这将如何影响您班级的行为?人受到保护,所以你真的不在乎它的状态。您应该注意会影响您班级用户的更改
  • 嗯,你说得对,加不加电话号码没关系。我需要测试的是当我调用 AddNumberToPersons(int index, PhoneNumber phoneNumber) 时。 Persons[index].AddNumber(phoneNumber);被执行。但是我仍然需要一个存根列表来执行该行而不抛出异常对吗?
  • 执行AddNumber 方法会如何影响你的类的行为?将电话号码添加到其中一个人后,它的行为会有所不同吗?
  • 不,它不需要,所以我不需要对 AddNumberToPersons 进行测试?如果我在 AddNumberToPersons 中重构了一些东西来阻止对 AddNumber 的调用,我不想要一个告诉我我破坏了 AddNumberToPersons 的测试吗?
  • 我不确定您是否要模拟或存根您正在测试的类的属性。如果有返回电话号码列表的 getter 或方法,请使用输出构建您的 Assert 并将其与您插入的内容进行比较。通常,您希望对复杂或连接的依赖项使用测试替身,而在单元测试中使用真实的东西会很麻烦。

标签: c# unit-testing nunit moq


【解决方案1】:

在 cmets 中有一些很好的讨论,关于为什么您可能要考虑您要测试的是什么。也就是说,在某些情况下,您确实希望设置您的类以使用其基类进行测试。在这种情况下,我不会使用 Moq,而是倾向于使用该类的手卷可测试版本。因此,在您的测试项目中,如果您可以像这样创建DerivedClass 的可测试版本:

public class TestableDerived : DerivedClass {
    public TestableDerived(List<Person> people) {
        this.Persons = people;
    }
    public List<Person> AccessablePersons { get { return this.Persons; } }
}

TestableDerived 类可以访问层次结构的protected 成员,因此您可以在测试的排列部分填充它。通常,您随后可以验证相应Person 的状态是否已更新以添加数字。这可能会给你一个类似这样的测试:

var sut = new TestableDerived(new List<Person>(){new Person(), new Person()});

sut.AddNumberToPersons(1, new PhoneNumber { Number = 1234 });

Assert.AreEqual(1, sut.AccessablePersons[1].Numbers.Where(x=>x.Number == 1234).Count());

在您的特定示例中,这是行不通的,因为您的 Person 类在添加电话号码后无法访问它们。您可以通过多种方式解决此问题,但这似乎不是您问题的重点,因此我选择相信这是您的示例代码中的一个遗漏,并添加了一个 Numbers 访问器。

【讨论】:

    猜你喜欢
    • 2012-01-26
    • 1970-01-01
    • 1970-01-01
    • 2011-10-23
    • 2021-05-31
    • 1970-01-01
    • 1970-01-01
    • 2020-06-30
    • 2013-10-10
    相关资源
    最近更新 更多