【问题标题】:how can I use @Enclosed without making methods as static如何在不将方法设为静态的情况下使用 @Enclosed
【发布时间】:2015-07-06 15:03:56
【问题描述】:

我需要有不同的参数集,所以我决定使用@Enclosed。但是,嵌套类必须是静态的,因此方法调用的所有现有方法/常量都必须是静态的。 但这很难,因为我无法更改所有这些方法的定义。

有没有什么方法可以使用@Enclosed 而不用静态添加现有方法的定义?

这是一个示例,以便您知道我在问什么。在示例中,由于 data() 是静态的,所以类 someTest 必须是静态的,所以如果我调用 nonStaticMethod(),我会在调用 nonStaticMethod( )。 但我不想将 nonStaticMethod() 重新定义为静态。

@RunWith(Enclosed.class)
public class EnclosedParameterizedTest extends EnclosedBase{

    @RunWith(Parameterized.class)
    public static class SomeTest {

        @Parameters
        public static Collection<Object[]> data() {
            return Arrays.asList(new Object[][]{
                    new Object[]{"NY"},
                    new Object[]{"CA"},
            });
        }

        String state;

        public SomeTest(String state) {
            this.state = state;
        }

        @Test
        public void verifyStateTest(){
            nonStaticMethod(); //a method already defined in parent of     
            //EnclosedBase which I cannot re-define
        }
    }
}

【问题讨论】:

    标签: java junit static inner-classes


    【解决方案1】:

    这是很多人感到困惑的事情。 “静态嵌套类”的全部含义是内部类没有对外部类的引用。不需要将方法或字段设为静态。

    例如,查找 java.util.HashMap 的源代码,有一个名为 Entry 的静态内部类实现了java.util.Map.Entry

    static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;
    
        /**
         * Creates new entry.
         */
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }
    
        public final K getKey() {
            return key;
        }
    
        public final V getValue() {
            return value;
        }
        // ... 
    

    显然,一个地图必须有多个条目,所以static 关键字没有被用来表示这是某种单例。

    【讨论】:

    • 谢谢@Nathan。我不确定我们是否在讨论同一件事。我已经编辑了原始帖子,希望您知道如何调用 nonStaticMethod() 而不将其重新定义为静态。
    • 谢谢@Nathan。没有Enclosed.class,我可以直接调用EnclosedParameterizedTest中的nonStaticMethod(),因为它是继承自EnclosedParameterizedTest的爷爷类的方法。奇怪的是,现在我必须调用 EnclosedParameterizedTest.this.nonStaticMethod()。顺便说一下 EnclosedParameterizedTest.this.nonStaticMethod() 不起作用。
    • @user389955:对,EnclosedParameterizedTest.this.nonStaticMethod 不起作用,因为在静态内部类中意味着没有对外部 this 的引用。
    【解决方案2】:

    不幸的是,Enclosed 运行器要求封闭的类是静态的(也称为“嵌套类”)。

    编辑:事实上,JUnit 永远不会实例化带有@RunWith(Enclosed.class) 注释的类。除非基类具有使用 JUnit 注释(@ClassRule@BeforeClass 等)注释的字段或方法,否则使用 Enclosed 扩展另一个类的测试不会做任何事情。

    我建议您通过委托而不是继承来共享代码。在您的情况下,您可以将 nonStaticMethod() 移动到不同的类:

    @RunWith(Enclosed.class)
    public class EnclosedParameterizedTest {
    
        @RunWith(Parameterized.class)
        public static class SomeTest {
            public final Helper helper = new Helper();
    
            @Parameters
            public static Collection<Object[]> data() {
                return Arrays.asList(new Object[][] {
                        new Object[] { "NY" },
                        new Object[] { "CA" },
                });
            }
    
            String state;
    
            public SomeTest(String state) {
                this.state = state;
            }
    
            @Test
            public void verifyStateTest(){
                helper.nonStaticMethod();
            }
        }
    }
    

    一般来说,委托比继承更灵活。 Java 中继承的一个常见问题是一个类只能有一个基类。但是另一个问题是嵌套类不能访问外部类的状态,所以不能共享静态方法以外的代码。

    编辑:如果这不是一个选项,您的嵌套类可以扩展您的基类:

    @RunWith(Enclosed.class)
    public class EnclosedParameterizedTest {
    
        @RunWith(Parameterized.class)
        public static class SomeTest extends EnclosedBase {
    
            @Parameters
            public static Collection<Object[]> data() {
                return Arrays.asList(new Object[][] {
                        new Object[] { "NY" },
                        new Object[] { "CA" },
                });
            }
    
            String state;
    
            public SomeTest(String state) {
                this.state = state;
            }
    
            @Test
            public void verifyStateTest(){
                nonStaticMethod();
            }
        }
    }
    

    或者,如果您想为不同的测试设置不同的参数集,考虑使用JUnitParams runner

    @RunWith(JUnitParamsRunner.class)
    public class MyParameterizedTest extends EnclosedBase {
    
        @Parameters({"NY", 
                     "CA" })
        @Test
        public void verifyStateTest(String state) {
            nonStaticMethod();
        }
    }
    

    【讨论】:

    • 感谢 NamshubWriter。我必须从基类继承。这是我无法控制的。我仍在尝试了解 JUnitParams 有多好。
    • @user389955 我编辑了我的答案以澄清Enclosed 跑步者的局限性,并提供另一个建议的解决方案
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-03
    • 1970-01-01
    • 1970-01-01
    • 2017-12-11
    • 2012-12-31
    相关资源
    最近更新 更多