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

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

java.lang.IllegalStateException: Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?) 

Spring Aspects JAR看起来配置正确。 特别是,我在pom.xml文件中有以下内容:

  org.springframework spring-aspects ${spring.version}  

   true   org.springframework spring-aspects   1.6 1.6   

当没有从JUnit测试中调用时,使用实体类的类工作正常。 知道如何设置,以便从JUnit测试中注入实体管理器吗?

这是我的Test类(或多或少):

 public class ServiceExampleTest { @Test public void testFoo() { FooService fs = new FooServiceImpl(); Set foos = fs.getFoos(); } } 

这足以抛出exception。 FooServiceImpl类返回一个Set of Foo,其中Foo是一个实体类。 当应用程序以通常的方式运行时, getFoos()方法可以正常工作。 问题只出在unit testing的背景下。

对于Spring Roo来说,这是一个令人难以置信的恼人问题,我还没有想出正式的解决方案。

但是……这里有两个解决方法:

  • 将spring-aspects jar复制到项目中,然后将其添加到Projects AspectJ Aspect Path
  • 使用Maven运行unit testing(并错过绿色条:()

对于选项1右键单击您的项目,选择Properties-> AspectJ Build – > Aspect Path选项卡。

ponzao是对的。 通过让我的测试类扩展AbstractJunit4SpringContextTests,我能够拥有所有的spring注入魔法。

例如

 @ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" }) public class SelfRegistrationTest extends AbstractJUnit4SpringContextTests { 

您的unit testing类应该具有@MockStaticEntityMethods注释。

只是想通过@migue为上述答案添加更多细节,因为我花了一段时间才弄明白如何让它工作。 该网站http://java.dzone.com/articles/mock-static-methods-using-spring-aspects确实帮助我得出了以下答案。

以下是我通过测试类注入实体管理器的方法。 首先使用@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 foos = fs.getFoos(); } 

这意味着当您调用fs.getFoos()时,AnnotationDrivenStaticEntityMockingControl将注入您的模拟实体管理器,因为Foo.entityManager()是一个静态方法。

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

所以说例如Foo有一个名为“getAllBars(Long fooId)”的静态find方法,当调用fs.getFoos()时会调用它,然后你需要执行以下操作才能使AnnotationDrivenStaticEntityMockingControl工作。

 @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 expectedBars = new ArrayList(); expectedBars.add(new Bar(1)); expectedBars.add(new Bar(2)); AnnotationDrivenStaticEntityMockingControl.expectReturn(expectedBars); FooService fs = new FooServiceImpl(); Set foos = fs.getFoos(); } 

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

您的unit testing类应该具有@MockStaticEntityMethods注释。

我也遇到了同样的exception,一切都配置正确。 我删除了项目并在STS(SpringSource Tool Suite)中再次重新导入它,这个问题就消失了。

不知道为什么要修复它,但这个问题可能是由于在我的情况下切换到STS之前使用Eclipse来管理Roo生成的项目。

问题很久之后,但是当我尝试从Eclipse中运行Spring Roounit testing时,我有一个有效的解决方案…

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

    mvn clean package

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

  mvn clean package -Dmaven.test.skip=true 

4.一旦包成功,然后在Eclipse中刷新。

您现在应该能够在Eclipse中成功运行unit testing。 我发现编辑实体导致了实体管理器错误的最大频率。 当我没有编辑它们时,我可以编辑其他类,unit testing将继续成功运行。

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'); } } } 

使用这样的Address类:

 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; }