有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java重载静态导入

在测试类中,我想为我自己的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 *是“类型BarTest中的方法assertEquals(Bar, Bar)不适用于参数(int, int)。”


共 (4) 个答案

  1. # 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());
        }
    }
    
  2. # 2 楼答案

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

    问题在于,在两个不同的名称空间中有两个assertEquals()方法——一个存在于组织中。朱尼特。断言名称空间,组织中的另一个名称空间。福。酒吧BarTest名称空间(当前名称空间)

    由于shadowing rules declared in the Java Language Specification错误,编译器会报告该错误。Assert的静态导入。assertEquals()被BarTest类中声明的assertEquals()隐藏

    修复方法(总是在隐藏声明的情况下)是使用FQN(完全限定名)。如果您打算使用assertEquals(…)对于JUnit Assert类,使用

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

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

    assertEquals(...)
    

    只在巴特斯特,那里有阴影。在所有其他只需要两个断言之一的类中。assertEquals()或BarTest。asserEquals(),您可以导入Assert或BarTest(我认为您不需要在其他地方导入BarTest,但还是声明了这一点)

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

    需要考虑的其他事情

    断言。assertEquals()在内部使用参数类的equals()方法。在测试用例中声明assertEquals()违反了DRY原则,因为类型为equals()的方法应该得到一致的实现和使用——在源代码和单元测试中使用两种不同的实现必然会导致混淆

    最好的方法是在Bar上实现equals(),然后使用Assert。测试用例中的assertEquals()。如果你已经有了,你就不需要物物交换。assertEquals()。assertEquals()的伪代码有点像下面的代码

    1. 如果两个参数都为null,则返回true
    2. 如果expected不为null,则在expected上调用equals(),将actual作为参数传递。如果对象相等,则返回true
    3. 如果对象不相等,则抛出带有格式化消息的AssertionError
  3. # 3 楼答案

    this.assertEquals(a,b);
    

    或者

    BarTest.assertEquals(a,b);
    

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

  4. # 4 楼答案

    对于在单元测试中调用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;并使用自定义逻辑

    抱歉,这并没有直接回答问题,而且更针对你的例子。根据我对问题的评论,我建议反对这种做法