Java 如何在SpringRoo中使用JUnit测试?(EntityManager的问题)

Java 如何在SpringRoo中使用JUnit测试?(EntityManager的问题),java,junit,spring-roo,entitymanager,Java,Junit,Spring Roo,Entitymanager,我正在尝试为SpringRoo项目编写JUnit测试。如果我的测试需要使用实体类,我会得到以下异常: java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?) SpringAspectsJAR看起来配置正确。特别是,我在pom.xml文件中有以下内容: <depen

我正在尝试为SpringRoo项目编写JUnit测试。如果我的测试需要使用实体类,我会得到以下异常:

java.lang.IllegalStateException: Entity manager has not been injected 
(is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
SpringAspectsJAR看起来配置正确。特别是,我在
pom.xml
文件中有以下内容:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>${spring.version}</version>
</dependency>

org.springframework
春季方面
${spring.version}


真的
org.springframework
春季方面
1.6
1.6
当不是从JUnit测试调用时,使用实体类的类工作正常。知道我如何设置实体管理器以便从JUnit测试中注入吗

这是我的测试课(或多或少):

公共类服务ExampleTest{
@试验
公共void testFoo(){
FooService fs=新的FooServiceImpl();
Set foos=fs.getFoos();
}
}

这足以引发异常。FooServiceImpl类返回一组Foo,其中Foo是一个实体类。当应用程序以常规方式运行时,
getFoos()
方法起作用。这个问题只出现在单元测试的环境中。

这是SpringRoo的一个令人非常恼火的问题,我还没有找到正式的解决方案

但是。。。以下是两种解决方法:

  • 将SpringAspectsJAR复制到项目中,然后将其添加到项目AspectJ方面路径中
  • 使用Maven运行单元测试(并错过绿色条:()

对于选项一,右键单击您的项目,选择属性->AspectJ构建->方面路径选项卡。

ponzao是正确的。通过让我的测试类扩展AbstractJunit4SpringContextTests,我可以拥有所有的spring注入魔法

e、 g


您的单元测试类应该有@MockStaticEntityMethods注释。

我也遇到了相同的异常,并且所有配置都正确。我删除了项目,并在STS(SpringSource工具套件)中重新导入了它,这个问题就消失了

我不确定为什么会这样做,但这个问题可能是因为在我的例子中,在切换到STS之前使用Eclipse管理Roo生成的项目造成的


单元测试类应该有@MockStaticEntityMethods注释

我只是想通过@migue为上面的答案添加更多细节,因为我花了一段时间才弄明白如何让它发挥作用。该网站确实帮助我得出了下面的答案

下面是我通过测试类注入实体管理器所做的工作。首先用@MockStaticEntityMethods注释您的测试类,并创建MockEntityManager类(这是一个仅实现EntityManager接口的类)

然后,您可以在ServiceExampleTest测试类中执行以下操作:

@Test
public void testFoo() {
  // call the static method that gets called by the method being tested in order to
  // "record" it and then set the expected response when it is replayed during the test
  Foo.entityManager();
  MockEntityManager expectedEntityManager = new MockEntityManager() {
    // TODO override what method you need to return whatever object you test needs
  };
  AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedEntityManager);

  FooService fs = new FooServiceImpl();
  Set<Foo> foos = fs.getFoos();
}
@测试
公共void testFoo(){
//调用被测试方法调用的静态方法,以便
//“记录”它,然后在测试期间重播时设置预期响应
Foo.entityManager();
MockEntityManager expectedEntityManager=新建MockEntityManager(){
//TODO覆盖返回测试所需对象所需的方法
};
AnnotationDriveInstantityLockingControl.expectReturn(expectedEntityManager);
FooService fs=新的FooServiceImpl();
Set foos=fs.getFoos();
}
这意味着当您调用fs.getFoos()时,AnnotationDrivenStaticEntityLockingControl将注入您的模拟实体管理器,因为Foo.entityManager()是一个静态方法

还请注意,如果fs.getFoos()调用实体类(如Foo和Bar)上的其他静态方法,则它们也必须指定为此测试用例的一部分

例如,假设Foo有一个名为“getAllBars(Long fooId)”的静态查找方法,该方法在调用fs.getFoos()时被调用,那么您需要执行以下操作才能使AnnotationDriveStaticEntityLockingControl工作

@Test
public void testFoo() {
  // call the static method that gets called by the method being tested in order to
  // "record" it and then set the expected response when it is replayed during the test
  Foo.entityManager();
  MockEntityManager expectedEntityManager = new MockEntityManager() {
    // TODO override what method you need to return whatever object you test needs
  };
  AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedEntityManager);

  // call the static method that gets called by the method being tested in order to
  // "record" it and then set the expected response when it is replayed during the test
  Long fooId = 1L;
  Foo.findAllBars(fooId);
  List<Bars> expectedBars = new ArrayList<Bar>();
  expectedBars.add(new Bar(1));
  expectedBars.add(new Bar(2));
  AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedBars);

  FooService fs = new FooServiceImpl();
  Set<Foo> foos = fs.getFoos();
}
@测试
公共void testFoo(){
//调用被测试方法调用的静态方法,以便
//“记录”它,然后在测试期间重播时设置预期响应
Foo.entityManager();
MockEntityManager expectedEntityManager=新建MockEntityManager(){
//TODO覆盖返回测试所需对象所需的方法
};
AnnotationDriveInstantityLockingControl.expectReturn(expectedEntityManager);
//调用被测试方法调用的静态方法,以便
//“记录”它,然后在测试期间重播时设置预期响应
长食物=1L;
Foo.findallbar(fooId);
List expectedBars=new ArrayList();
预期条形图。添加(新条形图(1));
预期条形图。添加(新条形图(2));
AnnotationDrivenStaticEntityLockingControl.expectReturn(expectedBars);
FooService fs=新的FooServiceImpl();
Set foos=fs.getFoos();
}

请记住,AnnotationDrivenStaticEntityLockingControl的顺序必须与fs.getFoos()调用其静态方法的顺序相同。

这个问题已经问了很久了,但我在尝试从Eclipse中运行Spring Roo单元测试时有了一个可行的解决方案

  • 在Eclipse中打开项目
  • 在Eclipse中,Project>Clean>Rebuild(自动或手动都无所谓)
  • 重新构建完成后,在控制台窗口中,让Maven清理并重新打包(需要清理):

    mvn清洁包装

  • 或者如果您的单元测试在maven中失败(并且您需要Eclipse来调试您的测试)

    4.包成功后,在Eclipse中刷新


    您现在应该能够在Eclipse中成功运行单元测试。我发现编辑实体导致实体管理器错误的频率最高。当我不编辑它们时,我可以编辑其他类,单元测试将继续成功运行。

    这对我使用Spring Roo很有效:

    import static org.junit.Assert.assertEquals;
    
    import org.junit.Test;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
    
    import com.jitter.finance.analyzer.domain.Address;
    
    @ContextConfiguration(locations = { "classpath*:/META-INF/spring/applicationContext*.xml"})
    public class EmTest extends AbstractJUnit4SpringContextTests {
    
        @Test
        public void checkEm(){
            Address a = new Address();
            a.setName("Primo");
            a.persist();
    
            Address b = new Address();
            b.setName("Secondo");
            b.persist();
    
            for(Address ad : Address.findAllAddresses()){
                System.out.println(ad.getName());
                assertEquals(ad.getName().charAt(ad.getName().length()-1), 'o');
            }
        }
    }
    
    使用如下地址类:

    import org.springframework.roo.addon.javabean.annotations.RooJavaBean;
    import org.springframework.roo.addon.javabean.annotations.RooToString;
    import org.springframework.roo.addon.jpa.annotations.activerecord.RooJpaActiveRecord;
    
    @RooJavaBean
    @RooToString
    @RooJpaActiveRecord
    public class Address {
        private String name;
    }
    

    你能把你的测试课也发出来吗
    @Test
    public void testFoo() {
      // call the static method that gets called by the method being tested in order to
      // "record" it and then set the expected response when it is replayed during the test
      Foo.entityManager();
      MockEntityManager expectedEntityManager = new MockEntityManager() {
        // TODO override what method you need to return whatever object you test needs
      };
      AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedEntityManager);
    
      // call the static method that gets called by the method being tested in order to
      // "record" it and then set the expected response when it is replayed during the test
      Long fooId = 1L;
      Foo.findAllBars(fooId);
      List<Bars> expectedBars = new ArrayList<Bar>();
      expectedBars.add(new Bar(1));
      expectedBars.add(new Bar(2));
      AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedBars);
    
      FooService fs = new FooServiceImpl();
      Set<Foo> foos = fs.getFoos();
    }
    
      mvn clean package -Dmaven.test.skip=true
    
    import static org.junit.Assert.assertEquals;
    
    import org.junit.Test;
    import org.springframework.test.context.ContextConfiguration;
    import org.springframework.test.context.junit4.AbstractJUnit4SpringContextTests;
    
    import com.jitter.finance.analyzer.domain.Address;
    
    @ContextConfiguration(locations = { "classpath*:/META-INF/spring/applicationContext*.xml"})
    public class EmTest extends AbstractJUnit4SpringContextTests {
    
        @Test
        public void checkEm(){
            Address a = new Address();
            a.setName("Primo");
            a.persist();
    
            Address b = new Address();
            b.setName("Secondo");
            b.persist();
    
            for(Address ad : Address.findAllAddresses()){
                System.out.println(ad.getName());
                assertEquals(ad.getName().charAt(ad.getName().length()-1), 'o');
            }
        }
    }
    
    import org.springframework.roo.addon.javabean.annotations.RooJavaBean;
    import org.springframework.roo.addon.javabean.annotations.RooToString;
    import org.springframework.roo.addon.jpa.annotations.activerecord.RooJpaActiveRecord;
    
    @RooJavaBean
    @RooToString
    @RooJpaActiveRecord
    public class Address {
        private String name;
    }