Harold L. Brown
Harold L. Brown

Reputation: 9966

Equivalent to DataJpaTest for Spring Data's ReactiveCrudRepository and R2DBC

For JpaRepository there is @DataJpaTest. @DataJpaTest allows for simple and isolated testing of JPA repositories in Spring.

We are using spring-data-r2dbc. Is there an equivalent of @DataJpaTest for ReactiveCrudRepository to test it in isolation?

Upvotes: 2

Views: 1978

Answers (2)

dbaltor
dbaltor

Reputation: 3383

Four years on and we still can't use @DataR2dbcTest to integration test reactive code with automatic rollbacks just like we do with @DataJpaTest. You can find here a great discussion about this.

This is how I implemented integration tests using R2DBC following the solution presented in the thread above:

  • Create the test fixture:
import org.springframework.stereotype.Component;
import org.springframework.transaction.reactive.TransactionalOperator;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Component
public class RxTransaction {

    private static TransactionalOperator rxtx;

    public RxTransaction(TransactionalOperator rxtx) {
        RxTransaction.rxtx = rxtx;
    }

    public static <T> Mono<T> withRollback(Mono<T> publisher) {
        return rxtx.execute(tx -> {
                    tx.setRollbackOnly();
                    return publisher;
                })
                .next();
    }

    public static <T> Flux<T> withRollback(Flux<T> publisher) {
        return rxtx.execute(tx -> {
            tx.setRollbackOnly();
            return publisher;
        });
    }
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.transaction.reactive.TransactionalOperator;

@Configuration
public class RxTxTestConfiguration {

    @Bean
    public RxTransaction rxTransaction(TransactionalOperator transactionalOperator) {
        return new RxTransaction(transactionalOperator);
    }
}
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.test.StepVerifier;

public interface TxStepVerifier extends StepVerifier {

    static <T> FirstStep<T> withRollback(final Mono<T> publisher) {
        return StepVerifier.create(publisher.as(RxTransaction::withRollback));
    }

    static <T> FirstStep<T> withRollback(final Flux<T> publisher) {
        return StepVerifier.create(publisher.as(RxTransaction::withRollback));
    }
}
  • Use TxStepVerifier in your tests to automatically rollback the db changes. Here is an example:
@DataR2dbcTest
@Import(RxTxTestConfiguration.class)
class IntegrationTest {

    @Autowired
    private AccountRepository accountRepository;

    @Test
    public void test() {
        // Given
        accountRepository.save(accountWith("1000.00", "USD"))
        // When
        .then(accountRepository.findAll())
        // Then
        .as(TxStepVerifier::withRollback)
        .expectNextCount(1)
        .verifyComplete());
    }
}

Upvotes: 0

mp911de
mp911de

Reputation: 18127

Yes, as of Spring Boot 2.3 you can use @DataR2dbcTest to spin up a context for your R2DBC repositories (including the DatabaseClient):

@DataR2dbcTest
class DataR2dbcTestIntegrationTests {

    @Autowired
    private DatabaseClient databaseClient;

    @Autowired
    private ConnectionFactory connectionFactory;

    @Autowired
    private MyRepository myRepository;

    @Test
    void testDatabaseClient() {
        this.databaseClient.execute("SELECT * FROM example").fetch().all()
             .as(StepVerifier::create).verifyComplete();
    }

    // …
}

Upvotes: 6

Related Questions