2

我在测试 CompanyService 的 findCompany() 方法的测试类中创建了以下四个测试。

@Test
public void findCompany_CompanyIdIsZero() {
    exception.expect(IllegalArgumentException.class);
    companyService.findCompany(0);
}
@Test
public void findCompany_CompanyIdIsNegative() {
    exception.expect(IllegalArgumentException.class);
    companyService.findCompany(-100);
}
@Test
public void findCompany_CompanyIdDoesntExistInDatabase() {
    Company storedCompany = companyService.findCompany(100000);
    assertNull(storedCompany1);
}

@Test
public void findCompany_CompanyIdExistsInDatabase() {
    Company company = new Company("FAL", "Falahaar");

    companyService.addCompany(company);

    Company storedCompany1 = companyService.findCompany(company.getId());
    assertNotNull(storedCompany1);
}

我的理解是,前三个是单元测试。他们测试 findCompany() 方法的行为,检查该方法将如何响应不同的输入。第四个测试虽然放在同一个班级,但实际上对我来说似乎是一个集成测试。它要求首先将公司添加到数据库中,以便以后可以找到它。这引入了外部依赖项 - addCompany() 和数据库。

我走对了吗?如果是,那么我应该如何对现有对象进行单元测试?只是模拟服务来“找到”一个?我认为这会扼杀测试的意图。

我很感激这里的任何指导。

4

2 回答 2

1

我是这样看的:你在这里测试的“单元”是CompanyService. 从这个意义上说,您的所有测试对我来说都像是单元测试。但是,在您的服务下方,可能还有另一个服务(您提到数据库),此测试也在执行?这可能会开始模糊集成测试的界限,但是您必须问自己是否重要。您可以删除任何此类基础服务,并且您可能希望:

  1. 底层服务的设置或使用速度很慢,使您的单元测试速度太慢。
  2. 您希望确保此测试的行为不受底层服务的影响 - 即此测试仅在CompanyService.

以我的经验,只要底层服务足够快,我就不会太担心我的单元测试依赖它。我不介意将一点集成泄漏到我​​的单元测试中,因为它有好处(更多的集成覆盖率)并且很少引起问题。如果它确实引起了问题,您可以随时返回并添加存根以改善隔离。

于 2013-02-25T23:15:33.050 回答
1

[1,2,3,4] 可以是基于单元的(模拟 | 不模拟)和基于集成的测试。这取决于你想测试什么。

  • 为什么要使用模拟?正如Jason Sankey所说...仅测试服务层而不是底层层
  • 为什么要使用模拟?你的业务逻辑可以有最多种形式。因此,您可以为一种服务方法编写多个测试,例如。创建人员(无地址 - 异常,无银行账户 - 异常,人员未填写非空属性 - 异常)。

你能想象每个测试都请求数据库来测试所有可能的异常状态(没有地址、没有银行账户等)吗?为了测试所有异常状态,填充数据库的工作太多。为什么不使用模拟对象,例如。表现得像不包含预期值的“残缺”对象。每个测试构造自己的“残缺”模拟对象。

模拟各种状态 === 您的测试将尽可能简单,因为每种测试方法将只测试一个状态。这些测试将清晰且易于理解和维护。如果我写一个测试,这是我想要达到的目标之一。

于 2013-02-27T13:52:59.320 回答