4

在测试类中,我想为自己的重载assertEquals提供一些不依赖于Object.equals. 不幸的是,这不起作用,因为一旦我assertEquals在本地声明我的方法,Java 就再也找不到静态导入org.junit.Assert.*了。

有没有解决的办法?即有没有办法为静态导入的方法提供额外的重载?(相当明显的解决方案是以不同的方式命名该方法,但该解决方案没有相同的美学吸引力。)

我的测试类文件如下所示:

package org.foo.bar;

import static org.junit.Assert.*;

import org.junit.Test;

public class BarTest {
    private static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }

    @Test
    public void testGetFoo() throws Exception {
        Bar a = new Bar();
        assertEquals(42, a.getFoo()); // Error *
    }

    @Test
    public void testCopyConstructor() throws Exception {
        Bar a = new Bar();
        // Fill a.
        Bar b = new Bar(a);
        assertEquals(a, b);
    }
}

Error *是“assertEquals(Bar, Bar)类型BarTest中的方法不适用于参数(int, int)。”</p>

4

4 回答 4

3

这个答案有两个部分 - 一个关于编译错误,另一个关于 assertEquals() 的用法

问题是在两个不同的命名空间中有两个 assertEquals() 方法——一个存在于 org.junit.Assert 命名空间中,另一个存在于 org.foo.bar.BarTest 命名空间(当前命名空间)中。

由于Java 语言规范中声明的遮蔽规则,编译器会报告该错误。Assert.assertEquals() 的静态导入被 BarTest 类中声明的 assertEquals() 遮蔽。

修复(总是在阴影声明的情况下)是使用 FQN(完全限定名称)。如果您打算使用 JUnit Assert 类的 assertEquals(...),请使用

org.junit.Assert.assertEquals(...)

当您需要使用您的声明时,只需使用

assertEquals(...)

仅在 BarTest 中,它被遮蔽。在只需要 Assert.assertEquals() 或 BarTest.asserEquals() 的所有其他类中,您可以导入 Assert 或 BarTest(我认为您不需要在其他地方导入 BarTest,但仍然如此说明)。

当没有阴影时,您可以简单地导入类或静态方法并在没有 FQN 的情况下使用它。

需要考虑的其他事项

Assert.assertEquals() 在内部利用参数类的 equals() 方法。在您的测试用例中声明 assertEquals() 违反了 DRY 原则,因为应该一致地实现和使用类型的 equals() 方法 - 在源代码和单元测试中放置两个不同的实现必然会引起混淆。

最好的方法是在 Bar 上实现 equals(),然后在测试用例中使用 Assert.assertEquals()。如果您已经拥有,则不需要 BarTest.assertEquals()。assertEquals() 的伪代码有点像下面

  1. 如果两个参数都为 null,则返回 true。
  2. 如果预期不为空,则在预期传递实际作为参数时调用 equals()。如果对象相等,则返回 true。
  3. 如果对象不相等,则抛出带有格式化消息的 AssertionError。
于 2009-09-19T15:26:49.200 回答
3

对于您在单元测试中调用的特定示例,一种可能的解决方案是assertEquals(Bar, Bar)使用提供静态方法的类来扩展类,如下所示:

class BarAssert extends Assert {
  public static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }
}

然后,您可以包含import static BarAssert.assertEquals;并使用您的自定义逻辑。

抱歉,这并没有直接回答问题,而是更针对您的示例。根据我对该问题的评论,我建议不要使用这种方法。

于 2009-09-19T15:38:39.553 回答
1

唯一的方法是完全限定其中一个。

import static org.junit.Assert.*;

import org.junit.Test;

public class BarTest {

    private static void assertEquals(Bar expected, Bar other) {
        // Some custom logic to test equality.
    }

    @Test
    public void testGetFoo() throws Exception {
        Bar a = new Bar();
        org.junit.Assert.assertEquals(42, a.getFoo());
    }
}
于 2009-09-19T15:23:41.967 回答
0
this.assertEquals(a,b);

或者

BarTest.assertEquals(a,b);

我会选择第一个,因为尽管它是一个静态方法,但您必须有一个实例才能使用它(它是私有的),并且this不会受到未来重命名的异想天开的影响。

于 2009-09-19T15:53:00.793 回答