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

时间:2010-07-19 19:52:48

标签: java junit spring-roo entitymanager

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

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文件中有以下内容:

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

<plugin>
  <configuration>
  <outxml>true</outxml>
  <aspectLibraries>
    <aspectLibrary>
      <groupId>org.springframework</groupId>
        <artifactId>spring-aspects</artifactId>
    </aspectLibrary>
  </aspectLibraries>
  <source>1.6</source>
  <target>1.6</target>
  </configuration>
</plugin>

并且在未从JUnit测试调用时,使用实体类的类可以正常工作。知道如何设置,以便从JUnit测试注入实体管理器吗?

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

public class ServiceExampleTest {

  @Test
  public void testFoo() {
    FooService fs = new FooServiceImpl();
    Set<Foo> foos = fs.getFoos();
  }
}

这足以抛出异常。 FooServiceImpl类返回一个Foo,其中Foo是一个实体类。当应用程序以通常方式运行时,getFoos()方法有效。问题只出在单元测试的背景下。

7 个答案:

答案 0 :(得分:6)

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

e.g。

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

答案 1 :(得分:3)

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

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

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

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

答案 2 :(得分:3)

  

您的单元测试类应该有@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<Foo> 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<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();
}

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

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

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

答案 5 :(得分:0)

问题发布后很长时间,但是当我尝试从Eclipse中运行Spring Roo单元测试时,我有一个有效的解决方案......

  1. 让项目在Eclipse中打开
  2. 在Eclipse中,Project&gt;清洁&gt;重建(自动或手动并不重要)
  3. 重新构建完成后,在控制台窗口中,让Maven清理并重新打包(需要清理):

    mvn clean package

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

      mvn clean package -Dmaven.test.skip=true
    

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

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

答案 6 :(得分:0)

这适用于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;
}