解决测试问题

首先我们要知道assertequals(期望,结果)这个函数的本质就是比较期望和结果是否相等,所以结果就是一个数而已,我们可以先int一个A,然后将结果放进A中再去比较。

那么之前提到的void函数怎么处理呢,总而言之,我们想要得到得是一个结果,我们只需要将void先进行运算得出一个结果在去进行比较就可以:

例如:

对于 void 函数(即不返回任何值的函数),我们通常关注它是否按照预期执行了某些操作,比如修改对象的状态、产生特定的输出等。当 void 函数需要手动输入输入数值时,我们需要在测试方法中模拟这些输入。

下面是一个使用 JUnit 测试 void 函数的例子,假设我们有一个 void 函数 calculateSum,它接收两个整数作为输入,并将它们的和存储在一个类的字段中:

java复制代码

public class Calculator {
private int sum;
public void calculateSum(int a, int b) {
sum = a + b;
}
public int getSum() {
return sum;
}
}

为了测试这个函数,我们可以创建一个 JUnit 测试类,并使用 assertEquals 或其他断言方法来验证 calculateSum 方法是否正确执行了。由于 calculateSum 是 void 的,我们不能直接对其返回值进行测试,但我们可以检查 Calculator 类的状态是否按照预期改变。

java复制代码

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class CalculatorTest {
private Calculator calculator;
@BeforeEach
public void setUp() {
// 在每个测试方法执行前初始化 Calculator 对象
calculator = new Calculator();
}
@Test
public void testCalculateSum() {
// 设置输入值
int a = 5;
int b = 10;
// 调用 void 方法
calculator.calculateSum(a, b);
// 验证状态是否改变
// 在这种情况下,我们检查 sum 字段是否等于输入值的和
int expectedSum = a + b;
int actualSum = calculator.getSum();
// 使用断言方法验证结果
assertEquals(expectedSum, actualSum, "The sum is not calculated correctly.");
}
}

在上面的测试类中,@BeforeEach 注解的方法 setUp 在每个测试方法执行之前都会被调用,用于初始化 Calculator 对象。然后,在 testCalculateSum 测试方法中,我们调用 calculateSum 方法,并传递一些硬编码的输入值。接着,我们通过调用 getSum 方法来获取计算后的和,并使用 assertEquals 断言来验证计算的结果是否符合预期。

请注意,如果你的 void 函数依赖于用户输入(比如从控制台读取),那么你可能需要重构你的代码以便能够更容易地进行单元测试。通常,这意味着将用户输入抽象为参数,或者至少将其封装在一个可以从测试中模拟的接口或类中。这样,你就可以在测试中提供模拟的输入,而不是依赖于实际的用户输入。

还有一个问题是,如果我的测试函数需要手动输入一些值,(也就是运用了Scanner这个东西),那我们应该如何测试呢?要知道在测试中我们没有办法打开控制台去手动输入。

在JUnit中测试带有Scanner s = new Scanner(System.in);的函数时,会遇到一个主要问题:JUnit测试是自动运行的,而System.in通常用于从控制台接收手动输入。因此,在测试环境中,我们不能依赖实际的控制台输入。

为了解决这个问题,我们可以采取以下几种策略:

1. 重构代码以使用依赖注入

最佳实践是将Scanner对象作为参数传递给需要它的方法或构造函数,而不是直接在方法内部创建它。这样,在测试时,我们可以传入一个模拟的Scanner对象。

java复制代码

import java.util.Scanner;
public class MyClass {
public int readInput(Scanner scanner) {
int input = scanner.nextInt();
// 使用输入执行某些操作
return input;
}
}
// 在测试中
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import java.util.Scanner;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
public class MyClassTest {
@Test
public void testReadInput() {
Scanner mockScanner = Mockito.mock(Scanner.class);
when(mockScanner.nextInt()).thenReturn(42); // 模拟输入42
MyClass myClass = new MyClass();
int result = myClass.readInput(mockScanner);
assertEquals(42, result); // 断言结果是否符合预期
}
}

2. 使用System规则的替代

如果你不能或不想重构代码,你可以使用如PowerMock这样的库来模拟静态方法调用,例如System.in。但是,请注意,这通常被视为一种不那么优雅的方法,因为它涉及到了更多的复杂性,并可能使测试更难理解和维护。

3. 使用ByteArrayInputStream

另一种方法是使用ByteArrayInputStream来模拟System.in的输入流。这不需要额外的库,但同样需要对System.in进行一些操作,这可能在某些情况下被视为不太好的做法。

java复制代码

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Scanner;
public class MyClass {
public int readInput() {
Scanner scanner = new Scanner(System.in);
int input = scanner.nextInt();
scanner.close();
return input;
}
}
// 在测试中
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import static org.junit.jupiter.api.Assertions.assertEquals;
public class MyClassTest {
private final InputStream systemInBackup;
private final ByteArrayInputStream in;
public MyClassTest() {
this.systemInBackup = System.in;
this.in = new ByteArrayInputStream("42\n".getBytes());
}
@BeforeEach
public void setUp() {
System.setIn(in);
}
@AfterEach
public void tearDown() {
System.setIn(systemInBackup);
}
@Test
public void testReadInput() {
MyClass myClass = new MyClass();
int result = myClass.readInput();
assertEquals(42, result);
}
}

在这个例子中,我们在测试开始之前备份了System.in,然后在测试运行时将其替换为ByteArrayInputStream,该流包含我们想要模拟的输入("42\n")。测试结束后,我们再将System.in恢复为原始状态。

总结

最佳实践是重构代码以支持依赖注入,这样你就可以轻松地传入模拟对象进行测试。如果你不能重构代码,那么使用ByteArrayInputStream来模拟System.in可能是一个可行的替代方案,但请注意这增加了测试的复杂性和潜在风险。使用PowerMock或其他类似库来模拟静态方法调用通常是最后的手段,应该尽量避免。

  • 8
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值