问题
I'm trying to write a JUnit test for a Spring Roo project. If my test requires use of the entity classes, I get the following Exception:
java.lang.IllegalStateException: Entity manager has not been injected
(is the Spring Aspects JAR configured as an AJC/AJDT aspects library?)
The Spring Aspects JAR looks to be configured correctly. In particular, I have the following in the pom.xml
file:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>${spring.version}</version>
</dependency>
and
<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>
and the classes that use the entity classes work fine, when not called from a JUnit test. Any idea how I can set things up so that the Entity manager is injected from a JUnit test?
Here is my Test class (more or less):
public class ServiceExampleTest {
@Test
public void testFoo() {
FooService fs = new FooServiceImpl();
Set<Foo> foos = fs.getFoos();
}
}
This is enough to throw the exception. The FooServiceImpl class returns a Set of Foo, where Foo is an entity class. The getFoos()
method works when the application is run in the usual way. The problem only comes in the context of unit tests.
回答1:
This is an incredibly annoying problem with Spring Roo and I have not figured out the official solution for.
But ... here are two workarounds:
- Copy the spring-aspects jar to your project then add it to your Projects AspectJ Aspect Path
- Use Maven to run your unit tests (and miss the green bar :( )
For option one Right click on your project select Properties-> AspectJ Build -> Aspect Path Tab.
回答2:
ponzao is correct. I am able to have all the spring injection magic by having my test class extend AbstractJunit4SpringContextTests.
e.g.
@ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" })
public class SelfRegistrationTest extends AbstractJUnit4SpringContextTests {
回答3:
Your unit test class should have @MockStaticEntityMethods annotation.
Just wanted to add more detail to the above answer by @migue as it took me a while to figure out how to get it to work. The site http://java.dzone.com/articles/mock-static-methods-using-spring-aspects really helped me to derive the answer below.
Here is what I did to inject entity manager via test class. Firstly annotate your test class with @MockStaticEntityMethods and create MockEntityManager class (which is a class that just implements EntityManager interface).
Then you can do the following in your ServiceExampleTest test class:
@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();
}
This means when you called fs.getFoos() the AnnotationDrivenStaticEntityMockingControl will have injected your mock entity manager as Foo.entityManager() is a static method.
Also note that if fs.getFoos() calls other static methods on Entity classes like Foo and Bar, they must also be specified as part of this test case.
So say for example Foo had a static find method called "getAllBars(Long fooId)" which gets called when fs.getFoos() get called, then you would need to do the following in order to make AnnotationDrivenStaticEntityMockingControl work.
@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();
}
Remember the AnnotationDrivenStaticEntityMockingControl must be in the same order that fs.getFoos() calls its static methods.
回答4:
Your unit test class should have @MockStaticEntityMethods annotation.
回答5:
I was also running into the same exception and everything was configured correctly. I removed the project and reimported it again in STS (SpringSource Tool Suite) and this problem went away.
Not sure why this fixed it but this issue could have been caused by use of Eclipse to manage the Roo generated project before switching to STS in my case.
回答6:
Long time after the question but I have a working solution when trying to run Spring Roo unit tests from within Eclipse...
- Have the project open in Eclipse
- In Eclipse, Project > Clean > Rebuild (Automatic or Manual doesn't matter)
Once the re-build is complete, in a console window, have Maven clean and re-package (Clean is required):
mvn clean package
or if your unit tests are failing in maven (and you need Eclipse for debugging your tests)
mvn clean package -Dmaven.test.skip=true
4. Once the package is successful, then refresh back in Eclipse.
You should be able to run unit tests successfully back in Eclipse now. I found editing entities caused the greatest frequency of the entity manager error. When I stayed clear of editing them, I could edit other classes and unit tests would continue to run successfully.
回答7:
This worked for me with 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');
}
}
}
With Address class like this:
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;
}
来源:https://stackoverflow.com/questions/3284496/how-to-use-junit-tests-with-spring-roo-problems-with-entitymanager