【问题标题】:Unit tests, can you test a single method?单元测试,你能测试单个方法吗?
【发布时间】:2013-12-03 21:42:36
【问题描述】:

我可能会问一些非常明显的问题。我在编写单元测试方面没有太多经验,因此出现了以下问题,让我开始思考。

说,你有一个类,这个类有你想测试的方法。但是你能一次测试一个方法吗?我想不是。为了测试该方法,您需要调用一个或多个其他方法。例如:

class MyClass { 
    int x;
    void foo() { x = 4; }
    boolean bar() { x = 3; }
    boolean check() { return x == 4; }
}

为了测试 foo 和 bar,我需要使用 check(),另一方面,为了测试 check,我需要使用 foo() 或 bar()。

说,我必须遵循测试用例:

class MyClassTest {
    @Test
    void testFoo() {
        MyClass obj = new MyClass();
        obj.foo();
        assert obj.check();
    }
}

现在假设,我的同事更改了 check() 方法:

boolean check() { return x == 5; }

当然,testFoo() 会失败,可能有人会认为 foo 方法有问题。

所以这看起来像鸡蛋一样的情况。人们通常如何解决这个问题?

【问题讨论】:

  • 工作单位是什么?这通常是它适用于测试的范围......有时它就像单一方法一样简洁,但通常您需要创建一个“夹具”或“套件”来定义您的“工作单元”。

标签: java unit-testing testing


【解决方案1】:

在这里独立测试方法可能没有多大意义,因为类的状态可以根据调用方法的顺序而改变。在这种情况下,我会确保行为(或状态转换)按预期工作。请参考以下三个正确指定类行为的测试:

class WhenFooWasCalled {
    @Test
    public void ThenCheckShouldReturnTrue {
        MyClass sut = new MyClass();
        sut.foo();
        assertTrue(sut.check());
    }
}

class WhenBarWasCalled {
    @Test
    public void ThenCheckShouldReturnFalse {
        MyClass sut = new MyClass();
        sut.bar();
        assertFalse(sut.check());
    }
}

class WhenNothingWasCalled {
    @Test
    public void ThenCheckShouldReturnFalse {
        MyClass sut = new MyClass();
        assertFalse(sut.check());
    }
}

更新:我添加了第三个测试用例:如果 foo() 和 bar() 都没有被调用, check() 的行为如何。

【讨论】:

  • 在两个不同的类中进行这些测试是个好主意吗?
  • @siledh 这完全取决于你,只是风格问题。我更喜欢 BDD 类型的方法,它可以帮助我像句子一样阅读类名 + 方法名,例如WhenFooWasCalled.ThenCheckShouldReturnTrue().
  • 所以我的假设是错误的,每个方法都应该有一个测试方法,而你只测试那个方法?
  • @DavidFrank 没错,但它无助于指定类的行为。您希望该类以特定方式运行,具体取决于在调用 check() 之前调用了哪些方法。所以这是你应该测试的。
  • +1 用于测试行为。测试单个方法,因为“你必须”表明你的类的设计没有写一些东西,并且设计过程(甚至很快在你的脑海中运行)还没有被考虑过。您可能已经测试过每种方法,但它们真的有什么用吗?
【解决方案2】:

您不会为个别方法编写测试,而是为个别需求编写测试。在这种情况下,您的班级似乎有两个要求:

  1. check 必须在最后一次调用 foo 时返回 true
  2. check 必须在最后一次调用 bar 时返回 false

因此,您将编写两个单元测试,每个要求一个以验证该类是否正确满足它(您可能想要制定第三个要求:check 在两者都没有被调用时应该做什么)。当您的同事进行上述更改时,他既没有破坏foo 方法,也没有破坏check 方法。他打破的是第一个要求。现在他必须以某种方式改变课程,以便它再次实现它。他如何做到这一点(更改foo,更改check或两者)并不重要。

【讨论】:

  • 你确实回答了我的问题,表明我不应该测试方法,而是测试行为。
【解决方案3】:

这对于具有内部可变状态的类很常见。我认为您的问题归结为在给定的状态操作序列之后您的单元测试行为是否正确。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-15
    • 2014-11-08
    相关资源
    最近更新 更多