【问题标题】:How to use JUnit tests with Spring Roo? (Problems with EntityManager)如何在 Spring Roo 中使用 JUnit 测试? (EntityManager 的问题)
【发布时间】:2010-07-19 19:52:47
【问题描述】:

我正在尝试为 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 测试中注入实体管理器吗?

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

public class ServiceExampleTest {

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

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

【问题讨论】:

  • 您也可以发布您的测试课程吗?我从未使用过 Spring Roo,但对于普通的 Spring 测试,您通常必须扩展 AbstractSpringJUnit4Test(或其他东西)或通过注释使用自定义 Spring 运行器进行测试。

标签: java junit spring-roo entitymanager


【解决方案1】:

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

例如

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

【讨论】:

    【解决方案2】:

    这是 Spring Roo 的一个非常烦人的问题,我还没有找到官方的解决方案。

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

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

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

    【讨论】:

    • 我会接受这个答案,但我无法轻松验证它,因为我不再使用 Roo。 (我在做另一份工作。)
    • @FarmBoy 你不能不说你现在使用的东西就这么说:)
    • 注意,你可以在Eclipse的Maven Dependencies下找到spring-aspects jar,右键添加到inpath。无论如何,这对我有用。我猜接受的答案完成了同样的事情。
    【解决方案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)”的静态查找方法,它在调用 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() 调用其静态方法的顺序相同。

    【讨论】:

      【解决方案4】:

      你的单元测试类应该有@MockStaticEntityMethods 注解。

      【讨论】:

        【解决方案5】:

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

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

        【讨论】:

          【解决方案6】:

          问了很久,但是当我尝试从 Eclipse 中运行 Spring Roo 单元测试时,我有一个可行的解决方案......

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

            mvn clean package

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

            mvn clean package -Dmaven.test.skip=true
          

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

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

          【讨论】:

            【解决方案7】:

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

            【讨论】:

              猜你喜欢
              • 2023-03-03
              • 2021-05-28
              • 2023-04-11
              • 1970-01-01
              • 2022-01-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2012-11-23
              相关资源
              最近更新 更多