如何在JUnit中测试void方法

soat7uwm  于 2023-11-19  发布在  其他
关注(0)|答案(3)|浏览(172)

由于我必须在公司里写测试,我们必须为每个可以测试的方法写单元测试。我现在的问题是,我有一个方法的返回值为void,下面是该方法当前的外观:

public void saveCarDriver(CarDriverDto carDriver) {
    BOCarDriver bo = CarDriver.findByCarDrivernoI(carDriver.getId());
    if (bo == null) {
        bo = new BOCarDriver();
    }
    CarDriverDtoMapper.copyToBo(bo, carDriver);
    save(bo);
}

字符串
这是方法本身,现在这里是JUnit测试,到目前为止我尝试过,但当然没有工作:

@Test
public void saveCarDriverShouldFindOneCarDriverIfOneWasCreatedBeforeTheMethod() {
    Transaction trans = new Transaction();
    DDCarDriverRow carDriverRow = new DDCarDriverRow();
    carDriverRow.setCarDrivernoi(1);
    DARow.saveToTransaction(carDriverRow, trans);
    trans.execute();
    
    CarDriverDto dto = new CarDriverDto();
    dto.setId(1);
    assertEquals(1, this.testy.saveCarDriver(dto).getSize());
}

qni6mghb

qni6mghb1#

你的代码看起来不像是为可测试性而设计的。虽然你总是可以尝试使用集成测试(她:使用与数据库的真实的连接执行代码,并查看它是否具有预期的影响),但这不允许仅对该方法进行非常孤立的测试。
请注意,你必须区分“JUnit测试”和“单元测试”。第一个是一个框架,用于实现测试结果的Assert,并执行测试,但它不强制执行“单元测试”。
一个“单元测试”是一个测试,它测试一个可公开访问的源代码单元,并且只测试这个单元,没有对其他单元的任何实际调用。在Java中,作为“可公开访问”,我认为每个方法都不具有private可见性。
为了隔离测试的代码单元(在本例中是方法public void saveCarDriver(CarDriverDto carDriver)),您必须“模拟”外部的所有内容,最好是可以验证对外部内容的所有调用并控制其返回值。
一个被广泛使用的框架是Mockito。还有其他的框架,但我只熟悉这一个。
对于mocking,您的代码存在依赖于许多static方法的问题,比如CarDriver.findByCarDrivernoICarDriverDtoMapper.copyToBo。这使得用模拟代码替换这两个方法的实现变得不必要地困难-这是可能的,但是如果你有任何机会将它们更改为非static方法,我会去做的-它将增加使用它们的所有代码的可测试性。
通常你inject提供这些方法的示例到包含这些方法的类。这意味着你将它们作为构造函数参数提供,并将它们存储为成员字段。依赖注入框架,如Spring或Google Guice,可以帮助注解,这样你就不必手工提供所有这些。
在测试中,您提供模拟而不是真实的类,那么在测试中,您可以

  • 验证是否使用预期参数调用了外部方法。
  • 控制执行测试方法中的所有代码路径。

对于你的方法,这意味着你有两个测试:
1.让findByCarDrivernoI返回一个常规示例,并检查该示例是否传递给copyToBo方法。
1.让findByCarDrivernoI返回null,并检查是否仍然调用了copyToBo
由于save方法是您自己类的方法,它的测试是很微妙的。如果它是private,你必须把它的所有动作都包括在你的常规测试中,就好像它是你的方法的直接部分一样。你不能单独测试private方法或与它们的交互。否则(如果它不是public,你可以创建一个spy类来测试,只对save方法进行存根,而不对测试中的其余代码进行修改。然后你可以验证对save的调用。
我不能在这一个答案中给予一个关于单元测试、可测试性和依赖注入的完整介绍,但是你应该有一个粗略的概述。
所有描述的技术都是最先进的技术(既不是“尖端”技术,也不是“前沿”技术),所以你的同事应该已经知道它们,使用它们,并能够帮助你一点。

hwazgwia

hwazgwia2#

你可以测试这个方法是否抛出异常。你的方法将一个实体保存到数据库中,所以在保存过程中某些东西“可能”失败。

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

@Test
public void shouldNotFail() {
    Assertions.assertDoesNotThrow(() -> {
            // your method saveCarDriver() here
    });
}

字符串
IMO我不建议走这条路,也许想想你想实现什么,重写方法,这样它就可以返回一些你可以测试的东西。

41zrol4v

41zrol4v3#

save(...)是否返回任何内容?也许值得从save(...)返回一个布尔值来确定调用是否成功,随后从saveCarDriver(...)返回该值并在测试代码中对其运行Assert。
示例代码:

public boolean saveCarDriver(CarDriverDto carDriver) {
    BOCarDriver bo = CarDriver.findByCarDrivernoI(carDriver.getId());
    if (bo == null) {
        bo = new BOCarDriver();
    }
    CarDriverDtoMapper.copyToBo(bo, carDriver);
    return save(bo); 
}

字符串
测试代码:

@Test
public void saveCarDriverShouldFindOneCarDriverIfOneWasCreatedBeforeTheMethod() {
    Transaction trans = new Transaction();
    DDCarDriverRow carDriverRow = new DDCarDriverRow();
    carDriverRow.setCarDrivernoi(1);
    DARow.saveToTransaction(carDriverRow, trans);
    trans.execute();

    CarDriverDto dto = new CarDriverDto();
    dto.setId(1);
    assertTrue(this.testy.saveCarDriver(dto));
}

相关问题