Java 如何在内部测试类中注入spring上下文?或者还有什么其他的解决办法?

Java 如何在内部测试类中注入spring上下文?或者还有什么其他的解决办法?,java,spring,junit,Java,Spring,Junit,我有一个测试类,它的结构应该是内部/嵌套类。一个家伙建议我使用@RunWith(hierarchycalcontextrunner.class)来运行它。从我的跑步者那里 已经试过了,我更喜欢这个,我想继续使用它。我已经根据这个建议建立了我的班级。它在外部类中运行良好,内部的所有测试都运行良好。但内部类中的所有内容都会引发这样的问题: IllegalStateException: Failed to load ApplicationContext ... Caused by: java.lang

我有一个测试类,它的结构应该是内部/嵌套类。一个家伙建议我使用
@RunWith(hierarchycalcontextrunner.class)
来运行它。从我的跑步者那里 已经试过了,我更喜欢这个,我想继续使用它。我已经根据这个建议建立了我的班级。它在外部类中运行良好,内部的所有测试都运行良好。但内部类中的所有内容都会引发这样的问题:

IllegalStateException: Failed to load ApplicationContext
...
Caused by: java.lang.IllegalStateException: Neither GenericXmlContextLoader nor AnnotationConfigContextLoader was able to load an ApplicationContext from [MergedContextConfiguration@4aa22cc2 testClass = AbstractBaseEntityGenericDao_Test.Find_Method, locations = '{}', classes = '{}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{}', contextCustomizers = set[[empty]], contextLoader = 'org.springframework.test.context.support.DelegatingSmartContextLoader', parent = [null]]. 
MyTestClass:

    @ActiveProfiles(profiles = "test") 
    @RunWith(HierarchicalContextRunner.class) 
    @ContextConfiguration(classes = {
            PersistenceConfig.class,
            RootConfig.class }) 
    @WebAppConfiguration 
    @Transactional 
    @Rollback 

    public class AbstractBaseEntityGenericDao_Test {

        private static final String[] CUSTOMER_NAMES = {"Veronica", "Hanna", "Eric"};

        @ClassRule
        public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();

        @Rule
        public final SpringMethodRule springMethodRule = new SpringMethodRule();

        @Autowired
        private ApplicationContext applicationContext;

        @Autowired
        private SessionFactory sessionFactory;

        @Rule
        public ExpectedException thrown = ExpectedException.none();

        private AbstractClassStub abstractClassStub;

        private class AbstractClassStub extends AbstractBaseEntityGenericDao<NamedStubEntity> {

            public AbstractClassStub(SessionFactory sessionFactory) {
                setClassInstance(NamedStubEntity.class);
                this.sessionFactory = sessionFactory;
            }

            @Override
            public void create(NamedStubEntity entity) {
                super.create(entity);
            }

            @Override
            public Optional find(Long id) {
                return super.find(id);
            }

            @Override
            public void update(NamedStubEntity entity) {
                super.update(entity);
            }

            @Override
            public void remove(@NonNull Long id) throws EntityNotFoundException {
                super.remove(id);
            }

            @Override
            public void remove(NamedStubEntity entity) {
                super.remove(entity);
            }
        }

        @Before
        public void setUp() throws Exception {
            abstractClassStub = new AbstractClassStub(sessionFactory);

            DbTestUtil.resetAutoIncrementColumns(applicationContext, "base_stub_entity");

            //...
        }

        @After
        public void tearDown() throws Exception {
            //...
        }

        @Test
        public void find_outer_test() {
            //Successful
        }


        public class Find_Method {

            @Test
            public void find_must_return_entity_in_database_by_id() {
                //Unsuccessful
            }

            @Test
            public void find_must_throw_NullPointerException() {
                //Unsuccessful
            }

            @Test
            public void find_should_return_BaseStubEntity() {
                //Unsuccessful
            }

        } }
AbstractBaseEntityGenericDao_测试

@ActiveProfiles(profiles = "test")
@RunWith(HierarchicalContextRunner.class)
public class AbstractBaseEntityGenericDao_Test extends AbstractSpringTest {

    private AbstractClassStub abstractClassStub;

    private class AbstractClassStub extends AbstractBaseEntityGenericDao<NamedStubEntity> {

        public AbstractClassStub(SessionFactory sessionFactory) {
            setClassInstance(NamedStubEntity.class);
            this.sessionFactory = sessionFactory;
        }

        @Override
        public void create(NamedStubEntity entity) {
            super.create(entity);
        }

        //...
    }

    @Before
    public void setUp() throws Exception {
        abstractClassStub = new AbstractClassStub(sessionFactory);

        DbTestUtil.resetAutoIncrementColumns(applicationContext, "base_stub_entity");

        //...
    }

    @After
    public void tearDown() throws Exception {
        //...
    }

    @Test
    public void find_must_find() {
        //Successful
    }

    public class Find_Method extends AbstractSpringTest {

        @Test
        public void find_must_throw_NullPointerException() {
            //Unsuccessful
        }

        @Test
        public void find_should_return_BaseStubEntity() {
            //Unsuccessful
        }

    }
}
@ActiveProfiles(profiles=“test”)
@RunWith(HierarchycalContextRunner.class)
公共类AbstractBaseEntityGenericDao_测试扩展了AbstractSpringTest{
私有抽象类存根抽象类存根;
私有类AbstractClassStub扩展了AbstractBaseEntityGenericDao{
公共抽象类存根(SessionFactory SessionFactory){
setClassInstance(namedSubEntity.class);
this.sessionFactory=sessionFactory;
}
@凌驾
公共void创建(namedSubEntity){
超级创建(实体);
}
//...
}
@以前
public void setUp()引发异常{
abstractClassStub=新的abstractClassStub(sessionFactory);
resetAutoIncrementColumns(applicationContext,“base_stub_entity”);
//...
}
@之后
public void tearDown()引发异常{
//...
}
@试验
public void find_must_find(){
//成功的
}
公共类Find_方法扩展了AbstractSpringTest{
@试验
public void find_must_throw_NullPointerException(){
//不成功
}
@试验
public void find_应_返回_BaseStubEntity(){
//不成功
}
}
}
它在调试器中的外观。调试器甚至不进入内部方法。它停在班级一级
我曾尝试将内部类设置为静态,以使其在外部可见,但
HierarchycalContextRunner
停止查看嵌套类中的测试方法。

您已经非常接近了。事实上,您的方法甚至可能是正确的,因为问题与配置文件有关,而不是与测试本身有关

广义地说,最简单的方法是将相关注释也放在嵌套类上,我认为这是您想要避免的

使其更干净的一种方法是让您的测试类都继承自一个公共类。然后,带注释的类将成为公共类。这对我来说尤其有效,因为我甚至不必在每次测试中编写所有不同的Spring注释。 这将要求您将
@ClassRule
@Rule
注释与
SpringClassRule
SpringMethodRule
@RunWith(Enclosed.class)
或类似内容结合使用。。。就像你已经在做的那样

在您的情况下,
Find_方法
类必须从
AbstractSpringTest
类继承,而该类又将使用
@WebAppConfiguration
和相关注释进行注释。但是请注意,
Find_方法
类应声明为
static

以下是此类设置的部分摘录:

package mypackage;

import org.junit.Rule;
import org.springframework.test.context.junit4.rules.SpringMethodRule;

import org.junit.ClassRule;
import org.springframework.test.context.junit4.rules.SpringClassRule;

import ...

@WebAppConfiguration
@ContextConfiguration(classes = { TestConfigurationClass1.class, TestConfigurationClass2.class })
public class AbstractSpringTest {

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
}

@RunWith(Enclosed.class)
public class MyTestClass extends AbstractSpringTest {

  ...
  public static class MyNestedTestClass extends AbstractSpringTest {
    ...
  }

  public static class MyOtherNestedTestClass extends AbstractSpringTest {
    ...
  }
}

下面是您的测试类的外观:

package mypackage;

import org.junit.Rule;
import org.springframework.test.context.junit4.rules.SpringMethodRule;

import org.junit.ClassRule;
import org.springframework.test.context.junit4.rules.SpringClassRule;

import ...

@WebAppConfiguration
@ContextConfiguration(classes = { TestConfigurationClass1.class, TestConfigurationClass2.class })
public class AbstractSpringTest {

    @Rule
    public final SpringMethodRule springMethodRule = new SpringMethodRule();

    @ClassRule
    public static final SpringClassRule SPRING_CLASS_RULE = new SpringClassRule();
}

@RunWith(Enclosed.class)
public class MyTestClass extends AbstractSpringTest {

  ...
  public static class MyNestedTestClass extends AbstractSpringTest {
    ...
  }

  public static class MyOtherNestedTestClass extends AbstractSpringTest {
    ...
  }
}

不用说,使用“规则”可以让您拥有任何您认为适合您的目的的
@RunWith
注释。在我的例子中,我发现使用这种方法来运行参数化测试非常有用


但是,您描述的错误似乎指向加载相关配置文件时出现的问题(
application.properties
application context.xml
及类似文件)。一般建议是仔细检查所有配置文件是否位于
类路径的正确路径上,以供测试使用。请注意,这意味着,例如,检查
目标
目录的内容,以及排除IDE“发脾气”和拒绝适当管理特定资源的情况,最好的方法是运行
mvn干净安装

谢谢您的解决方案。它在内部类中抛出“NoSuchBeanDefinitionException:No'org.hibernate.SessionFactory'类型的限定bean”,外部类中的所有内容似乎都在工作。我已经将@Autowired字段删除到抽象类中,但仍然得到相同的异常。在调试器中,所有字段(SessionFactory、ApplicationContext、SpringMethodRule)均为空。在调试器中,内部类中的SpringMethodRule显示以下内容:((AbstractBaseEntityGenericDao_测试)this)。SpringMethodRule=不可转换类型;无法将'com.初学者课程.softcomputer.abstractions.persistence.dao.AbstractBaseEntityGenericDao_Test.Find_Method'强制转换为'com.初学者课程.softcomputer.abstractions.persistence.dao.AbstractBaseEntityGenericDao_Test'。请提供修改后的代码,以便我可以查看。与我的代码相比,我可以看到两个不同之处。不确定是不是这些问题,但值得一试,即使只是为了消除这些问题的根源。尝试将
HierarchycalContextRunner
替换为
封闭的
,并使两个嵌套的测试类
成为静态的
。如果可行,试着逐一重新介绍。如果它们不起作用,请在这里再次发表评论,我们将继续。我目前的猜测是,它无法加载其中一个或多个文件。验证它们相对于JUnit的路径,以确保它们位于预期位置。我偶尔发现有必要进行
mvn清理安装
,因为IDE并不总是复制这些文件,即使它应该这样做。通常,确保配置文件在运行时位于测试预期的位置。