【问题标题】:Why/how does JUnit pass tests with compiler errors?JUnit 为什么/如何通过编译器错误的测试?
【发布时间】:2014-05-15 17:32:08
【问题描述】:

我刚刚开始学习 TDD,并正在尝试以这种方式编写一个简单的项目。

我正在使用 Eclipse 和 JUnit,每次进行更改时,我都会运行相关包中的所有测试。

但是我很惊讶地在包资源管理器中看到我的一个测试用例有一个大红叉,表示编译器问题......很恼火,我认为我把我的 eclipse 快捷方式弄混了,并没有运行所有测试,因为它们都通过了。

但是当我开始摆弄时,我意识到即使有编译器错误,Eclipse + JUnit 似乎也会运行并通过测试......

JUnit 测试用例:

import static org.junit.Assert.*;

import org.junit.Before;
import org.junit.Test;

public class ATestCase {

    private Command command;
    private Invoker invoker;

    @Before
    public void setUp() throws Exception {

        command = new Command() {
            public void methodA(){};
            //haven't implemented methodB()
        };

        invoker = new Invoker(command);

    }

    @Test
    public void test(){
        invoker.invoke();
    }
}

interface Command{
    void methodA();
    void methodB();
}

调用者类:

class Invoker{

    private Command command;

    public Invoker(Command command) {
        this.command = command;
        //if I invoke methodB() I get UnresolvedCompilationError
    }

    public void invoke(){
        command.methodA();
        //only if I call methodB here
        //do I get Unresolved compilation problem
//      command.methodB();
    }
}

我在测试用例的setUp中创建的命令对象只实现了接口的一种方法。这当然会在 Eclipse 中导致编译错误警告。

但是,除非我在测试用例中实际调用该方法,否则测试通过。 如果我确实调用了该方法,那么测试会因“未解决的编译错误”而失败。

谁能给我解释一下到底发生了什么?

******编辑******

我不知道为什么它被关闭为重复。

显然我应该编辑这个问题以明确区别:

  • 嗯,我应该在第一行重复的问题是:

“java.lang.Error: Unresolved”的可能原因是什么 编译问题”?

  • 我的问题标题表明我在问:

JUnit 为什么/如何通过编译器错误的测试?

不应该编译的代码如何由JUnit运行而不导致错误? 我完全理解Unresolved Compilation Error 的原因,这是我的代码中的明显未解决的编译错误。我不明白的是如何错误总是发生(它只发生在我专门调用未实现的方法时)以及测试如何通过?!

可能这些问题是相关的,但除非有一个具体的答案来解释它们是如何相关的,否则我看不出它们是如何以任何方式重复的问题......

【问题讨论】:

  • 尝试关闭自动构建,然后选择“清理”,然后重新打开自动构建,看看是否仍然出现这种情况。
  • @durron597 感谢您的建议。我试过了,但它仍然运行并通过了测试。我认为这种行为不应该发生吗?
  • 另一个想法是因为方法没有编译,junit无法通过注解和反射识别方法,所以它甚至没有尝试运行它
  • @durron597 我最初认为可能会发生类似的事情,但您可以在屏幕截图中看到已经进行了 1/1 的测试运行。设置方法也必须已经运行,否则调用程序将为空,我会得到一个 NullPointerException。此代码是否在您的设置中显示相同的行为?

标签: java junit tdd


【解决方案1】:

当一个类未能实现接口方法时,Java 编译器不会拒绝该代码,而是为该方法发出字节码,这将引发运行时错误。这解释了为什么 JUnit 能够运行测试以及为什么如果您不调用 methodB 测试通过 - 不会引发运行时错误。

根据this page,默认情况下不会发生这种情况,但需要您启用 Java -> Debug 'Suspend execution on compiler errors' 设置。

【讨论】:

  • Eclipse 中的 Java 编译器执行此操作。独立 Javac 完全拒绝无效代码。
【解决方案2】:

我假设这是设计使然:允许测试特定方法,而不必担心编译器无论如何都会选择的其他依赖项是否已解决。
即我们不应该使用 JUnit 来告诉我们整个项目是否可以编译。

【讨论】:

  • 这并没有解释它是如何工作的。如果出现编译错误,JUnit 如何获取 .class 文件进行测试?
  • @AndrewMedico:感谢您提出这个问题。答案也很好!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-04
  • 2017-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多