如何使用服务和存储库为弹簧数据设置单元测试?

时间:2016-12-23 15:36:44

标签: java spring unit-testing

我已经检查了许多SO评论以及弹簧数据和单元测试的文档,但我无法使其工作,我不知道为什么它不起作用。

我有一个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   有资格成为autowire候选人。依赖注释:   {@ org.springframework.beans.factory.annotation.Autowired(所需=真)}

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

3 个答案:

答案 0 :(得分:1)

要注入的存储库bean,

  • 您需要使用其中一个弹簧数据注释启用存储库。因此,将@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)
        // ...
    }

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

我希望这会有所帮助

答案 1 :(得分:0)

您可以尝试添加

@ActiveProfiles("your spring profile") 

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

答案 2 :(得分:0)

你可以: