【问题标题】:How to set up a unit test for spring data with service and repository?如何使用服务和存储库为 Spring 数据设置单元测试?
【发布时间】:2016-12-23 15:36:44
【问题描述】:

我已经检查了许多 SO cmets 和文档中的 spring 数据和单元测试,但我无法让它工作,我不知道为什么它不工作。

我有一个如下所示的 junit 测试类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)
public class DealServiceTest {

    @Configuration
    static class ContextConfiguration {

        // this bean will be injected into the OrderServiceTest class
        @Bean
        public DealService orderService() {
            DealService dealService = new DealService();
            // set properties, etc.
            return dealService;
        }

        @Bean
        public EmployeeService employeeService(){
            EmployeeService employeeService = new EmployeeService();
            return employeeService;
        }

    }

    @Autowired
    DealService dealService;

    @Autowired
    EmployeeService employeeService;

    @Test
    public void createDeal() throws ServiceException {
        Employee employee = new Employee("Daniel", "tuttle", "danielptm@me.com", "dannyboy", "secret password", 23.234, 23.23);
        Deal d = dealService.createDeal("ADSF/ADSF/cat.jpg", "A title goes here", "A deal description", 23.22, "Name of business", 23.23,23.23, employee, "USA" );
        Assert.assertNotNull(d);

    }

}

然后我的服务类看起来像这样

@Service
public class DealService {

    @Autowired
    private DealRepository dealRepository;

    public Deal createDeal(String image, String title, String description, double distance, String location, double targetLat, double targetLong, Employee employee, String country) throws ServiceException {
        Deal deal = new Deal(image, title, description, distance, location, targetLat, targetLong, employee, country);
        try {
            return dealRepository.save(deal);
        }catch(Exception e){
            throw new ServiceException("Could not create a deal: "+deal.toString(), e);
        }
    }

    public Deal updateDeal(Deal d) throws ServiceException {
        try{
            return dealRepository.save(d);
        }catch(Exception e){
            throw new ServiceException("Could not update deal at this time: "+d.toString(),e);
        }
    }

    public List<Deal> getAllDealsForEmployeeId(Employee employee) throws ServiceException {
        try{
            return dealRepository.getAllDealsBy_employeeId(employee.getId());
        }catch(Exception e){
            throw new ServiceException("Could not get deals for employee: "+employee.getId(), e);
        }
    }

}

然后是我的存储库:

*/

public interface DealRepository extends CrudRepository<Deal, Long>{

    public List<Deal> getDealsBy_country(String country);

    public List<Deal> getAllDealsBy_employeeId(Long id);

}

我的配置文件如下所示:

@Configuration
@EnableJpaRepositories("com.globati.repository")
@EnableTransactionManagement
public class InfrastructureConfig {

    @Bean
    public DataSource dataSource() {
        HikariConfig config = new HikariConfig();
        config.setDriverClassName("com.mysql.jdbc.Driver");
        config.setJdbcUrl("jdbc:mysql://localhost:3306/DatabaseProject");
        config.setUsername("awesome");
        config.setPassword("database");
        return new HikariDataSource(config);
    }

//  @Bean
//  public DataSource derbyDataSource(){
//      HikariConfig config = new HikariConfig();
//      config.setDriverClassName("jdbc:derby:memory:dataSource");
//      config.setJdbcUrl("jdbc:derby://localhost:1527/myDB;create=true");
//      config.setUsername("awesome");
//      config.setPassword("database");
//
//      return new HikariDataSource(config);
//
//  }

    @Bean
    public JpaTransactionManager transactionManager(EntityManagerFactory factory) {
        return new JpaTransactionManager(factory);
    }

    @Bean
    public JpaVendorAdapter jpaVendorAdapter() {

        HibernateJpaVendorAdapter adapter = new HibernateJpaVendorAdapter();
        adapter.setDatabase(Database.MYSQL);
        adapter.setGenerateDdl(true);

        return adapter;
    }

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setDataSource(dataSource()); //Get data source config here!
        factory.setJpaVendorAdapter(jpaVendorAdapter());
        factory.setPackagesToScan("com.globati.model");

        return factory;
    }
}

但我收到此错误。

java.lang.IllegalStateException: 无法加载 ApplicationContext ...

原因: org.springframework.beans.factory.NoSuchBeanDefinitionException: 否 为依赖项找到了合格的 bean [com.globati.repository.DealRepository]:预计至少 1 个 bean 有资格作为自动接线候选者。依赖注解: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

任何关于如何使用 spring 数据、junit 以及我的服务和存储库成功进行单元测试的建议将不胜感激。谢谢!

【问题讨论】:

  • 如果您查看堆栈跟踪,似乎问题出在 EmployeeService(如果它使用 EmployeeRepository)而不是 DealService。

标签: java spring unit-testing


【解决方案1】:

对于要注入的存储库 bean,

  • 您需要使用 spring-data 注释之一启用存储库。所以将@Enable*Repositories 添加到你的配置类中

  • 您还需要配置 dB 工厂和其他相关 bean。我正在使用 Mongo,并且配置了 mongoDbFactory bean

  • 在大多数情况下,您的测试配置应该看起来像您的主要配置,除了不必要的 bean 被模拟实现替换

更新 这是我的代码(对不起,我的代码在 mongo 中,我想你可以联系)

@Configuration
@WebAppConfiguration
@ComponentScan(basePackages = "com.amanu.csa",
        excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = WebConfig.class))
@EnableMongoRepositories(repositoryImplementationPostfix = "CustomImpl")
class TestConfig {

    @Bean
    Mongo mongo() throws Exception {
        return new MongoClient("localhost")
    }

    @Bean
    MongoDbFactory mongoDbFactory() throws Exception {
        return new SimpleMongoDbFactory(mongo(), "csa_test")
    }

    @Bean
    MongoTemplate mongoTemplate() throws Exception {
        MongoTemplate template = new MongoTemplate(mongoDbFactory())
        template.setWriteResultChecking(WriteResultChecking.EXCEPTION)
        return template
    }
}

这是我的测试配置文件...正如您所见,它明确排除了我的主配置文件。

@ContextConfiguration(classes = TestConfig)
@RunWith(SpringRunner.class)
class OrganizationServiceTest {

    @Autowired
    OrganizationService organizationService

     @Test
    void testRegister() {
        def org = new Organization()
        //...
        organizationService.register(org)
        // ...
    }

那是我的测试课。它指的是测试配置,我建议使用命名配置类。您可以将通用选项放在超类上并扩展它们并将它们用于您的测试。

希望对你有帮助

【讨论】:

  • 谢谢。一个代码示例会很棒,因为我认为我已经完成了您的建议,但它仍然无法正常工作。
【解决方案2】:

你可以尝试添加

@ActiveProfiles("your spring profile") 

此外,我建议使用像 fladdoodle (https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo) 这样的嵌入式测试数据库

【讨论】:

    【解决方案3】:

    你可以:

    【讨论】:

    • 好的,相对于mysql,是否需要使用derby等嵌入式数据库?
    • 如果您使用 Jenkins 这样的持续集成解决方案,可能没有安装数据库
    猜你喜欢
    • 2019-03-20
    • 2014-08-13
    • 1970-01-01
    • 2011-01-10
    • 2016-06-30
    • 1970-01-01
    • 1970-01-01
    • 2011-10-16
    • 2021-02-13
    相关资源
    最近更新 更多