Spring - 在测试中替换 @Service bean

8

在我的Spring Boot应用程序中,我有一个带有@Service注释的服务bean,并且我想在特定的JUnit测试中模拟此服务(而不是在所有测试中)。如何仅替换此服务Bean进行一次特定测试?

服务声明如下:

@Service
public class LocalizationServiceImpl implements LocalizationService {
   ...
}

应用程序配置类:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackages="my.package")
@EntityScan

public class Application {
...
}

测试类:

@Transactional
@SpringApplicationConfiguration(classes = LocalizationServiceTest.LocalizationServiceTestConfig.class)
public class LocalizationServiceTest extends ESContextTest {

    @Autowired
    private LocalizationService locService;

    @Configuration  
    public static class LocalizationServiceTestConfig {

        @Bean
        public LocalizationService localizationServiceImpl() {
            return mock(LocalizationService.class);
        }

    }
}

同时测试类的父类:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public abstract class ESContextTest {
...
}

但这并不起作用。当我运行测试时,自动装配的locService属性使用的是原始的LocalizationServiceImpl。这出现在日志文件中: 跳过[BeanMethod:name = localizationService,declaringClass = ... LocalizationServiceTest $ LocalizationServiceTestConfig]的bean定义:已经存在bean 'localizationService'的定义。此顶级bean定义被视为覆盖。 当我在LocalizationServiceTestConfig中使用不同的@Bean方法名称,例如localizationServiceMock()(与原始实现类名不同)时,Spring会抛出异常。
'No qualifying bean of type is defined: expected single matching bean but found 2: localizationServiceImpl,localizationServiceMock'

我认为使用相同的名称是正确的。

唯一可行的解决方案是从LocalizationServiceImpl类中删除@Service注释,并创建正常(非测试)应用程序运行的配置,例如:

@Configuration 
public class BeansConfig {
    @Bean
    public LocalizationService localizationServiceImpl() {
        return new LocalizationServiceImpl();
    }
}

然后在测试运行中,正确的模拟实现将被自动装配。

但是通过@Service注释也应该可以做到同样的事情,不是吗?

感谢建议。

1个回答

11

我自己找到了一种解决方案:在 LocalizationServiceTestConfig 类中将 localizationServiceImpl() 重命名为例如 localizationServiceMock() 并使用 @Primary 注释该方法。

但是,为什么简单地重新定义具有相同“id”的 bean 就无法像通过 xml-config 那样工作呢?


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接