【问题标题】:How to test adding an element to an arraylist with junit如何使用junit测试将元素添加到arraylist
【发布时间】:2015-05-28 18:41:49
【问题描述】:


我想测试 addElement 方法:

public class MyClass {
    private List<Integer> ints = new ArrayList<>();

    public void addElement(int element) {
        ints.add(element);
    }
}

我需要测试我的元素是否被添加。根据类隔离,我不能使用任何 ArrayList 方法来检查它。事实上我应该模拟我的arrayList。但是,如果我模拟它并更改 get() 方法的行为以返回一些值,我无法确定我的元素是否在该列表中。

如何测试?

【问题讨论】:

  • 检查大小之前/之后?
  • 我不明白为什么你添加后不能 assertEquals(intsPreviousSize + 1, ints.size()) 。类隔离是什么意思?
  • mock部分也不清楚,如果你对list使用mock,你只需要“验证”add被调用了

标签: java unit-testing arraylist junit mocking


【解决方案1】:

assertEquals(intsPreviousSize + 1, ints.size()),并且有一个用于 ints ArrayList 的 getter 方法。如果你不能有一个 getter,那么你可以使用反射,如果你不能这样做,那么我认为你不能。

【讨论】:

    【解决方案2】:

    您想在心理而不是代码级别上测试什么?

    听起来您正在尝试验证 MyClass.addElement(int) 确实添加了一个元素。

    MyClass 还有哪些其他公共方法?如果没有,那么 真的 addElement(int) 是否真的添加了该元素,因为这两种可能的情况之间没有明显的区别。

    然后,我将假设 MyClass 有一些其他方法,它们的行为取决于 ints 的内容,您可以使用这些方法来确定 addElement(int) 是否符合预期。

    例如,如果ints 有一个getter,您可以简单地在addElement(int) 之前和之后调用它,然后比较这两个点的List 内容。

    或者,如果有一个方法可以总结 ints 中的值,您可以调用它并比较调用 addElement(int) 之前和之后返回的值,并确保差值等于您添加的 int。

    【讨论】:

    • 没错。重点应该放在您想要测试的所需行为上,如果没有其他公共方法,那么是否从 addElement 中删除所有代码都没有关系,因为可观察到的行为无法改变。 +1
    • 一个方法是否真的需要它自己的测试用例也是值得问问自己的。如果您正在为像 OP 问题中的方法一样简单的方法编写单元测试,那么您就是为了工作而做无用的工作。
    • 我怀疑它只是添加和检查那么简单。如果他有 if (element
    【解决方案3】:

    我建议创建MyClass 的子类,它具有某种类型的public 方法来检索ArrayList(或列表中的特定元素)。如果您想从子类访问ints 对象,还需要将其访问级别更改为protected。如果您希望它更紧一点,您可以使用默认范围,并要求您的新类与MyClass 在同一个包中。我以前做过,并且认为能够对您的代码进行单元测试是合理的成本。

    这样父类将被测试,但您可以使用子类从测试中检索信息。

    例如:

    public class MyClass {
        protected List<Integer> ints = new ArrayList<>();
        ...
    }
    
    public class MyClassChild extends MyClass {
        public List<Integer> getInts() {
            return ints;
        }
    }
    
    // Test code
    MyClassChild myClass = new MyClassChild();
    myClass.addElement(42);
    myclass.getInts().size() == 1;
    

    如果一切都失败了,您可以依靠反射来检索对象,但这更麻烦(在我看来)。

    【讨论】:

    • 虽然在技术上是一种正确的方法,但它是值得怀疑的。您不希望使用仅用于测试的派生类来膨胀您的代码库。 Mockito 和 PowerMock 框架已经提供了测试 void 方法的工具。
    • 也许我应该澄清一下——这个类不会包含在主代码库中(这将是一个糟糕的主意),这将在您的测试文件夹中的相应包中,这将保留测试生产代码之外的代码。
    • 如果您打算将其设为私有以受保护,那么我觉得您还不如只拥有一个公共 getter
    • @BrandonLing 我不同意。开放对变量的访问有很多级别,制作 defaultprotected 仍然与拥有公共 getter 不同。是的,这两个将使检索变量更容易,但不如公共 getter。
    • @mnd 当然,当然有一些用例,但我认为绝大多数都属于公共吸气剂,并且避免了创建子类​​等所有麻烦。
    【解决方案4】:

    关注您要测试的行为。在调用addElement 之后,MyClass 以何种外部可测试方式发生变化?这应该是您测试的重点。

    测试通常分为两类。

    • 测试状态变化
    • 测试交互

    在这种情况下,您似乎正在测试状态更改(尽管从您的缩减示例中这并不是 100% 清楚)。在测试状态更改时,您通常需要进行设置,执行一些操作,然后验证对象的状态是否已按预期方式更改。在这些测试中,您通常不需要模拟(尽管您可能需要存根来提供测试数据)

    在这种情况下,您将添加一个元素,然后调用一些额外的方法来验证该元素是否已添加,例如尝试获取它,或验证存储的元素数量是否增加。如果没有更多关于你的对象实际做什么的细节,很难准确地指导你。

    您的类中有一个私有数组列表这一事实是一个实现细节,不应成为您测试的重点,否则如果您决定将来更改数组列表以进行其他操作,您的测试可能需要更新.

    在测试交互时,您通常需要进行设置,执行一些操作,然后验证预期的交互是否发生。在这些测试中,您可能希望对正在测试的交互使用模拟。

    例如,您可能想要检查您的类与另一个类(如记录器或数据库访问类)的交互是否以预期的方式发生。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-11-04
      • 2021-03-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      相关资源
      最近更新 更多