如何存根 Spring 存储库以在集成测试中抛出异常?

How to stub Spring repository to throw an exception in an integration test?

我有一个服务,它有一个存储库作为构造函数的参数。

@Autowired
NodeServiceListInstallService( final BykiListRepository aBykiListRepository )

BykiListRepository 是默认的 Spring 存储库,没有实现

interface BykiListRepository extends JpaRepository<BykiList, Long> {
    //some magic methods
}

我的配置class标记为@EnableJpaRepositories,所以,我没有直接声明bean。服务声明:

@SpringBootApplication
@EnableConfigurationProperties( ApplicationProperties )
@EnableJpaRepositories
@EnableTransactionManagement
@ImportResource( 'classpath:META-INF/spring/application-context.xml' )
class Application extends SpringBootServletInitializer {
    @Bean
    NodeServiceListInstallService nodeServiceListInstallService( final BykiListRepository bykiListRepository ) {
        new NodeServiceListInstallService( bykiListRepository )
    }
}

我正在尝试在存储库方法 save 的调用中编写测试,将抛出异常 PersistenceException。 我已经尝试 stub/spy 一个存储库并在 @TestConfiguration@Primary 中将其声明为一个 bean,甚至实现接口。 但是我还没有得到结果。

@TestConfiguration
class TestConfig {
    @Bean
    BykiListRepository bykiListRepository() {
        //return Spock's Spy/Stub or new BykiRepositoryBadImpl()
    }

测试:

@ContextConfiguration( classes = TestConfig )
class GlobalErrorHandlerIntegrationTest extends BaseFlowIntegrationTest {
    //test()
}

我在 Groovy-2.4.12 上写,用 Spock-1.1 写测试。 Spring Boot 1.5.4。 保留变体是使用方面,但并不完全是我想要的。 非常感谢您的帮助。

更新:DetachedMockFactory的用法:

配置:

@TestConfiguration

class DummyConfiguration {
    private final detachedFactory = new DetachedMockFactory()
    @Bean
    @Primary
    BykiListRepository bykiListRepository() {
        detachedFactory.Mock( BykiListRepository )
    }
}

测试框架:

@SpringBootTest( classes = DummyConfiguration )
@Import( [DummyConfiguration] )
@ContextConfiguration( classes = DummyConfiguration )
class GlobalErrorHandlerIntegrationTest extends BaseFlowIntegrationTest {
    @Autowired
    BykiListRepository bykiListRepositoryMock
    def 'exercise error handling'() {
        given: 'the failing repository'
        bykiListRepositoryMock.save( _ ) >> {
            throw new CannotCreateTransactionException()
        }
        when: 'the message is send to rabbit'
        rabbitOperations.send( configuration.rabbitExchangeName, '', msg )
    }
}

其中:

@SpringBootTest( webEnvironment = SpringBootTest.WebEnvironment.NONE )
@ContextConfiguration( classes = Application )
class BaseFlowIntegrationTest extends AbstractIntegrationTest {...}

@Category( InboundIntegrationTest )
abstract class AbstractIntegrationTest extends Specification {...}

您可以像下面那样创建 test configuration 并在调用某些函数时使用 Spock 记录,然后将抛出 ex。当然,在测试 class 中使用 @Inject or @Autowire... 并执行 @Import([IntegrationTestMockingConfig])

@TestConfiguration
class IntegrationTestMockingConfig {

     private DetachedMockFactory factory = new DetachedMockFactory()

     @Bean
     ExternalRepository externalRepository() {
         factory.Mock(ExternalRepository)
     }
}

问题是因为我的bean 名称错误。我已将其更改为 bykiListRepositoryMock(而不是 bykiListRepository)并解决了问题。

如果您想使用模拟存储库抛出异常 -

when(repository.yourMethodName(anyString(), anyString(), anyString())).thenThrow(new PersistenceException("Persistence exception occurred"));

如果你想抛出任何特定的持久性异常,那么你也可以抛出。 https://www.objectdb.com/api/java/jpa/exceptions