我正在学习 Java(到目前为止是为了自我开发,然后是如何进行)。该类有一个方法可以开始生成一个可能很大的数组。并且有一种获取此数组的方法。分离的,用于在单独的线程中实现生成的方法。
public float[][] getTerra() {
if (task.isAlive()) {
try {
task.join(); //жду, чтобы terra сгенерилась до конца
} catch (InterruptedException ignored) { // <--- Codecov redline
//empty
}
}
return terra;
}
codecov(单元测试覆盖率)显示处理未以任何方式进行测试catch (InterruptedException)
。task
如果字符串是一个私有对象,并且不希望有外部访问,你怎么能用测试覆盖它呢?还是我错误地等待线程结束?
你真的应该重写数组生成算法本身,这既是因为返回值的不确定性,也是因为你无法测试它,特别是,你可以通过将它从一个单独的线程变成一个单独的线程来显着改进数组生成任务。
在这种特殊情况下,您的手脚被束缚有两个原因:
因此,只要您在调用上述方法之前不更改线程引用本身,或者您不将无限任务推送到该线程中,Java 正式有权在您尝试调用
InterruptedException
等待之前完成线程计算线。展望未来,这与所谓的密切相关。函数纯度:纯函数为每组输入参数返回确定性结果,并且没有外部影响(副作用,函数外部世界的任何状态变化)。您提供的方法与您无法直接控制的这些相同的副作用密切相关,严格来说,只能对或多或少的纯功能进行正式测试(因为否则无法验证并且维护成本高-如果代码绑定到外部状态,那么测试必须不可避免地在测试之前重新创建它)。
具体来说,在这种情况下,您无法以任何方式控制外部状态(在正确的时间执行或不执行线程),因为您的代码涉及直接调用以更改外部状态(启动线程);同时,在不参考外部状态的情况下,您无法测试您的代码。但是,如果您将任务的执行委托给其他人,那么您可以轻松地在测试中重新创建此状态。为了解决所有问题,我建议使用接口功能
ExecutorService
- 这是一项允许您注册任务以供其执行的服务,而接口本身并不能保证任务将在何处以及如何执行 - 它可以是相同的流、另一个流、另一台机器,或者它会打印出来在纸上并发送给数学家来解决。在这种情况下,您的代码可能如下所示:我会提前警告您,代码非常脏且不正确 - 除了任务委派的即时时刻。这里你发送一个任务给
ExecutorService
,它会找出去哪里执行任务,然后等待它完成。现在您可以在程序代码中使用其中一种方法的结果Executors.*
,并在测试中使用您自己的实现,这将返回Future
以下字符:因此,该方法的执行时间仅通过调用
.interrupt()
正在执行的线程并抛出相应的异常来限制,这是测试所需要的。现在您可以创建一个线程,调用它mapContainer.get()
并中断线程本身,以强制代码沿着指定的分支传递。没关系?
实际上,不是真的,因为代码仍然充满了对外部状态的调用,而建议的带有 Future 的版本,如果处理不当,真的会永远运行下去,这可能会挂掉你的 CI 服务器。但如果不在这里重建整个东西,我恐怕无法提供更好的选择。将 InterruptedException 视为阻止程序正常运行的东西会容易得多(只要你不
.interrupt
为自己的目的调用,它确实是)——在这种情况下,你可以而且应该抛出异常,在更高级别捕获它并终止程序。在任何情况下,您都应该努力保持代码整洁,因为除其他外,它有助于防止这种情况并将异常处理推到程序的外围(而不是将这种处理分散到所有组件)
作为后记:它甚至比上述所有内容都更好,可以应对任务
CompletableFuture
,但我决定不使已经歪曲的文本复杂化。