Announcement Announcement Module
Collapse
No announcement yet.
ROO-generated versus developer integration tests Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • ROO-generated versus developer integration tests

    I have a few ROO entities and their ROO-generated integration test cases execute as expected. Then I created a regular class (through ROO) - did not make it an entity since I wanted to manage its persistence. In another package, I developed a Repository class to manage its persistence and wrote an Integration test case for it myself. For this I followed the the Spring 3.0 documentation and PetClinic example, using an @ContextConfiguration that defaulted to <classname>-context.xml in the same directory as the RepositoryTest class. At this point, there are no web, security or any other types of classes.

    All the tests ran fine till I added the @Repository annotation to the Repository class. At that point, all the ROO generated integration tests started failing with an error message that the Repository bean could not be instantiated since it required a Hibernate SessionFactory. The reason is that Spring forcibly instantiates the Repository class when trying to run the entity integration tests (though it does not really need this class for the purposes of the test).

    I found two ways to "fix" the problem:
    1) Remove the @Repository annotation, which is far from desirable.
    2) In the <context:component-scan base-package="xyz"> section of the ROO generated META-INF/spring/applicationContext.xml, add the following exclude filter:
    <context:exclude-filter expression="org.springframework.stereotype.Reposit ory" type="annotation"/>

    The second option is fine with me for now, but that may change.

    A couple of questions regarding all this:

    1) Is there a better solution or approach that will enable the annotation and allow all the tests to run successfully?

    2) Both the classes and the integrations tests generated by ROO refer to META-INF/spring/applicationContext.xml. Is there a way to point the tests to another context file? I could then point them all to the same context file used by the Repository integration test, and maybe all the tests would work off of the same context.

    I say "maybe" because I did try adding the bean definition of the Repository class and its SessionFactory dependency to META-INF/spring/applicationContext.xml, but kept getting the same error.

    Regards!

  • #2
    I'd recommend you not use @Repository. Instead use @Component and also @PersistenceContext. The latter will cause the correct JPA EntityManager to be injected into your repository class. If you then require exception translation, take a look at https://jira.springsource.org/browse/SPR-6275 which provides it via AspectJ.

    There is no way of modifying the Roo-generated integration tests' @ContextConfiguration. However, you could use an <import> directive in the applicationContext.xml if required. Again, though, I'd recommend not using @Repository.

    Comment


    • #3
      Solved

      Hi Ben,

      Thanks for the reply. The @PersistenceContext and @PersistenceUnit allowed me to get rid of some superfluous getters and setters of EntityManager/EntityManagerFactory from my code.

      I found the cause of the original problem; turned out to be a user error after all. I had put the @Required annotation on the setter method of the SessionFactory in the Repository class, like this:

      Code:
          
          @Required
          public void setSessionFactory(SessionFactory sessionFactory)
          {
              this.sessionFactory = sessionFactory;
          }
      The @Required was forcing the load of the SessionFactory in the Roo generated integration tests. When I removed this annotation, all the tests run fine even with the @Repository annotation. Obviously it was not necessary. I must have added it after seeing some example on the net (it is not from the PetClinic example)

      A follow-up question: what is the reason you recommend not using @Repository?

      Thanks!

      Comment


      • #4
        I don't recommend @Repository as Spring will then create an AOP proxy object at startup time. That AOP proxy object exists primarily to perform exception translation, and as per my earlier reply because you use AspectJ in Roo apps you can benefit from the more efficient (speed and memory-wise) approach afforded by SPR-6275. Further @PersistenceContext is the JPA standard manner of requesting the injection of an EntityManager, so it's more standards-compatible to pursue that path. Having said that, the downsides of @Repository are pretty minor but nonetheless if you're after the cleanest and most efficient architecture it's preferable in my view to use SPR-6275 and @PersistenceContext.

        Comment


        • #5
          That helps! Thanks for the clarification.

          Comment


          • #6
            Just wanted to share something I discovered pertaining to the second question in my original post regarding the option of using the same context file for the Roo generated tests and the developer tests. In one of my integration tests, I added one of Roo generated persistence or finder methods, and the test kept failing the following error:

            "Entity manager has not been injected (is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)

            This of course, comes from the generated *_Roo_Entity.aj's static entityManager() method. After some digging around and post some trial & error, I realized from the verbose comments in the Roo-generated src/META-INF/applicationContext.xml that turning on load-time weaving using the XML configuration tag: <context:spring-configured/> might help. And sure enough, when I added this to my test's <classname>-context.xml, it worked!!!

            Taking it a step furthur, I imported the src/META-INF/applicationContext.xml into my test's context file, and started turning off the bean definitions, starting with the duplicate ones like the DataSource and the EntityManager. To my surprise, the dependencies still kept getting injected correctly and the tests ran successfully even when I got rid of all of them leaving behind just the import statement. So finally, I got rid of the <classname>-context.xml itself, and in the integration java source, changed the @Configuration annotation from
            Code:
            @Configuration
            to
            Code:
            @ContextConfiguration("classpath:META-INF/spring/applicationContext.xml")
            .

            Now the code and tests are all running off of the Roo generated, unmodified applicationContext file, and I have eliminated a bunch of unnecessary definition files in the process. I suppose I will have to resurrect the <classname>-context.xml only if the auto-wiring cannot/does not work due to multiple beans that match the criteria for DI, or some such scenario comes up.

            Pretty powerful stuff, and I am thankful for those verbose comments which clued me in on the solution. I have reproduced them here for quick reference:

            Code:
            <!--
            Turn on AspectJ @Configurable support. As a result, any time you
            instantiate an object, Spring will attempt to perform dependency
            injection on that object. This occurs for instantiation via the "new"
            keyword, as well as via reflection. This is possible because AspectJ
            is used to "weave" Roo-based applications at compile time. In effect
            this feature allows dependency injection of any object at all in your
            system, which is a very useful feature (without @Configurable you'd
            only be able to dependency inject objects acquired from Spring or
            subsequently presented to a specific Spring dependency injection
            method). Roo applications use this useful feature in a number of
            areas, such as @PersistenceContext injection into entities.
            -->
            <context:spring-configured/>
            Regards,
            Shyam.

            Comment


            • #7
              Thanks for sharing this Shyam!

              Cheers,
              Stefan

              Comment

              Working...
              X