【发布时间】:2015-04-11 11:41:40
【问题描述】:
我使用 Spring MVC 有一段时间,并使用了 JUnit。当我测试服务或 dao 时,我使用 @Autowired 注解进行 bean 注入,效果很好。请注意,我在测试和应用程序中使用相同的配置文件,以避免在测试运行后配置错误。
现在我必须使用 JBehave 进行服务层测试。我的 Spring MVC 已经有域、DAO、服务层的包。我还为 DAO 和服务创建了示例 JUnit 测试。但是 JBehave 没有运气。我使用了http://jbehave.org/ 中的“五步概述”,并且能够在没有@Autowired bean 的情况下运行JBehave 测试并且它成功运行、生成报告等等。现在我想将 DAO 和 Service 层中的 @Autowired bean 添加到 *Steps.java,但它们似乎没有在运行时实例化。
我还用 Google 搜索并查看了来自 http://jbehave.org/ 的 Spring 示例,但我发现所有示例都不起作用,并且 jbehave.org 中的示例对我来说看起来很乱。
所以现在我在 Spring Tool Suite (Eclipse) 的 MAVEN 上构建了 Spring MVC、Hibernate、JUnit、JBehave 的工作配置。问题是:如何在 *Steps.java 类中为 JBehave 测试使用 @Autowired 对象。
我不知道我要在这里放什么数据,所以如果有不足的地方请告诉我,我会添加它。
admin_service_story.story
Scenario: There is 0 in DB
Given In database there are 0 goods
When The controller calls list method of service
Then service returns with 0 elements list
AdminServiceStory.java // 我将它作为 JUnit 测试运行
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/META-INF/spring/root-context.xml")
public class AdminServiceStory extends JUnitStory{
private final CrossReference xref = new CrossReference();
public AdminServiceStory() {
configuredEmbedder().embedderControls().doGenerateViewAfterStories(true).doIgnoreFailureInStories(true)
.doIgnoreFailureInView(true).useThreads(2).useStoryTimeoutInSecs(60);
// Uncomment to set meta filter, which can also be set via Ant or Maven
// configuredEmbedder().useMetaFilters(Arrays.asList("+theme parametrisation"));
}
@Override
public Configuration configuration() {
Class<? extends Embeddable> embeddableClass = this.getClass();
Properties viewResources = new Properties();
viewResources.put("decorateNonHtml", "true");
// Start from default ParameterConverters instance
ParameterConverters parameterConverters = new ParameterConverters();
// factory to allow parameter conversion and loading from external
// resources (used by StoryParser too)
ExamplesTableFactory examplesTableFactory = new ExamplesTableFactory(new LocalizedKeywords(),
new LoadFromClasspath(embeddableClass), parameterConverters);
// add custom converters
parameterConverters.addConverters(new DateConverter(new SimpleDateFormat("yyyy-MM-dd")),
new ExamplesTableConverter(examplesTableFactory));
return new MostUsefulConfiguration()
.useStoryControls(new StoryControls().doDryRun(false).doSkipScenariosAfterFailure(false))
.useStoryLoader(new LoadFromClasspath(embeddableClass))
.useStoryParser(new RegexStoryParser(examplesTableFactory))
.useStoryPathResolver(new UnderscoredCamelCaseResolver())
.useStoryReporterBuilder(
new StoryReporterBuilder()
.withCodeLocation(CodeLocations.codeLocationFromClass(embeddableClass))
.withDefaultFormats().withPathResolver(new ResolveToPackagedName())
.withViewResources(viewResources).withFormats(Format.CONSOLE, Format.STATS, Format.TXT, Format.HTML, Format.XML)
.withFailureTrace(true).withFailureTraceCompression(true).withCrossReference(xref))
.useParameterConverters(parameterConverters)
// use '%' instead of '$' to identify parameters
.useStepPatternParser(new RegexPrefixCapturingPatternParser("%"))
.useStepMonitor(xref.getStepMonitor());
}
@Override
public InjectableStepsFactory stepsFactory() {
return new InstanceStepsFactory(configuration(), new AdminServiceSteps());
}
}
AdminServiceSteps.java
我用异常标记了字符串:goodDAO.save(good);//!!!这里发生异常 java.lang.NullPointerException !!!
@Component
public class AdminServiceSteps {
private static final String CATALOG_NUMBER_PREFIX = "Num_";
private static final String NAME_PREFIX = "Good name_";
private static final String DESCRIPTION_PREFIX = "Description_";
@Autowired
private AdminService adminService;
@Autowired
private GoodDAO goodDAO;
List<Good> goodsList;
@Transactional
@Given("In database there are %num goods")
public void putGoodsInDB(int num) {
Good good;
for (Integer i = 0; i< num; i++){
good = new Good();
good.setCatalogNumber(CATALOG_NUMBER_PREFIX+Integer.toString(i));
good.setDescription(DESCRIPTION_PREFIX+Integer.toString(i));
good.setName(NAME_PREFIX+Integer.toString(i));
goodDAO.save(good);//!!! here exception occurs java.lang.NullPointerException !!!
}
}
//@Transactional
@When("The controller calls list method of service")
public void controllerCallsList() {
//goodsList = adminService.list();
}
@Then("service returns with %num elements list")
public void checkGoodsListSize(int num) {
//assertEquals("Assert list size", num, goodsList.size());
}
}
Augusto 感谢您的想法。让我们看看发生了什么。我变了
public class AdminServiceStory extends JUnitStory implements ApplicationContextAware {
在类正文中:
...
ApplicationContext springContext;
@Override
public InjectableStepsFactory stepsFactory() {
return new SpringStepsFactory(configuration(), springContext);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
springContext = applicationContext;
}
当我查看调试器时,看起来 InjectableStepsFactory() 在 setApplicationContext() 之前运行,所以 springContext 变量尚未设置。
所以我明白了
java.lang.NullPointerException
at org.jbehave.core.steps.spring.SpringStepsFactory.stepsTypes(SpringStepsFactory.java:32)
at org.jbehave.core.steps.AbstractStepsFactory.createCandidateSteps(AbstractStepsFactory.java:34)
at org.jbehave.core.embedder.StoryManager.runBeforeOrAfterStories(StoryManager.java:90)
at org.jbehave.core.embedder.StoryManager.runStories(StoryManager.java:75)
at org.jbehave.core.embedder.Embedder.runStoriesAsPaths(Embedder.java:203)
at org.jbehave.core.junit.JUnitStory.run(JUnitStory.java:24)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:233)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:87)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:176)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
【问题讨论】:
标签: spring-mvc autowired jbehave