我试图“嘲笑”一个豆子 @SpringBootTest
.
@SpringBootTest
@ActiveProfiles("test")
@RunWith(SpringRunner.class)
public class SalesSummaryServiceTest {
@MockBean
private SalesSummaryMapper summmaryMapper;
@Autowired
private SalesSummaryService salesSummmaryService;
@Test
public void testGetMonthlySummary() {
// Removed for brevity
given(this.summmaryMapper.selectByPropDate(testSchema, testProp, testDate, testEnd)).willReturn(List.of(testSum, testSum));
var res = this.salesSummmaryService.getMonthlySummary(test, testProp, testDate.getMonthValue(), testDate.getYear());
// Removed for brevity
}
}
但是,测试失败(无法加载应用程序上下文),因为找不到唯一bean:
Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.midamcorp.data.dal.SalesSummaryMapper' available: expected single matching bean but found 2: salesSummaryMapper,com.midamcorp.data.dal.SalesSummaryMapper#0
被测班级是一个基础班 @Service
实施:
@Service
public class SalesSummaryServiceImpl implements SalesSummaryService {
private SalesSummaryMapper salesSumMapper;
@Autowired
public SalesSummaryServiceImpl(SalesSummaryMapper salesSumMapper) {
this.salesSumMapper = salesSumMapper;
}
@Override
public List<SaleSummary> getMonthlySummary(PropType propType, String propId, int monthVal, int yearVal) {
var startDate = LocalDate.of(yearVal, monthVal, 1);
var endDate = startDate.with(TemporalAdjusters.lastDayOfMonth());
return this.salesSumMapper.selectByPropDate(propType.getSchema(), propId, startDate, endDate);
}
}
这个 SaleSummaryMapper
dependency是一个简单的mybatisMap器:
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface SalesSummaryMapper {
}
我理解基本错误(例如,spring无法确定使用哪个bean,因为两个bean可以满足依赖性)。我不明白的是为什么“真正的”mapperbean没有被 @MockBean
当,根据文档:“上下文中定义的相同类型的任何现有单个bean将被mock替换”。我错过了什么?谢谢!
1条答案
按热度按时间sqyvllje1#
我认为问题可能与mybatis如何在spring上下文中注册bean有关。接口
SalesSummaryMapper
不是在spring上下文中创建的bean的类型。从mybatis文档示例中,我看到mapper实际上是MapperFactoryBean
:我假设当您使用任何类型的扫描器来注册带有
@Mapper
注解。所以
@MockBean
不替换Map器是因为它们不属于同一类型。编辑:我收回上面的内容。豆子将是相同的类型,因为
MapperFactoryBean
执行Spring的FactoryBean
. 可能在创建模拟bean的那一刻,工厂还没有创建bean?您可以首先用实际的
@Component
豆子。如果可以的话,你应该试着用名字而不是类型来模拟。在mybatis文档中,您可以阅读:
发现的Map器将使用spring自动检测组件的默认命名策略进行命名(请参阅spring参考文档(核心技术-命名自动检测组件-)。也就是说,如果找不到注解,它将使用Map器的未大写的非限定类名。但如果找到@component或jsr-330@命名注解,它将从注解中获取名称。注意,您可以将annotation属性设置为org.springframework.stereotype.component、javax.inject.named(如果您有jse6)或您自己的annotation(必须对其本身进行注解),这样annotation既可以作为标记,也可以作为名称提供者。
基于以上的潜在解决方案可以是将Map器另外标记为named
@Component
:在测试中使用
@Qualifier
```@MockBean
@Qualifier("salesSummaryMapper")
private SalesSummaryMapper summmaryMapper;