Nik
Nik

Reputation: 3

Quarkus Reactive/Hibernate Reactive test passes everytime, even when it should fail

I have a simple reactive CRUD application made with Quarkus while following these two articles: Getting started reactive and Hibernate reactive panache

I am trying to test my service methods, but before that I'm trying to see how the example test works. This is the example test from the article:

import io.quarkus.test.hibernate.reactive.panache.TransactionalUniAsserter;

@QuarkusTest
public class SomeTest {

    @Test
    @RunOnVertxContext
    public void testEntity(TransactionalUniAsserter asserter) {
        asserter.execute(() -> new MyEntity().persist()); 
        asserter.assertEquals(() -> MyEntity.count(), 1l); 
        asserter.execute(() -> MyEntity.deleteAll()); 
    }
}

When I try to replicate the test like below, the test always passes no matter what I set the expected count to.

Here is my test file with the test case that is green.

`@QuarkusTest
@RunOnVertxContext
class AuthorServiceTest {

    @Inject
    AuthorService service;

    @Test
    @RunOnVertxContext
    public void testGetAllAuthors(TransactionalUniAsserter a) {
        a.execute(() -> new Author("J.K.", "Rowling", LocalDate.of(1965, 7, 31)).persist());
        a.assertEquals(Author::count, 3L);
        a.execute(Author::deleteAll);
    }
}`

I am also trying to find out how to test service methods that return Uni types. I can't find any resources online that show this. Most of the ways to test seem to throw No current Vertx context found.

Here is how my model looks like:

@NoArgsConstructor
@AllArgsConstructor
@Getter
@Setter
@Entity
@Table(name = "authors")
public class Author extends PanacheEntity {

    @Column(nullable = false)
    private String name;
    @Column(nullable = false)
    private String surname;
    @Column(nullable = false)
    private LocalDate dateOfBirth;

}

Here is my service:

import io.quarkus.hibernate.reactive.panache.Panache;
import io.quarkus.panache.common.Sort;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.core.Response;
import um.feri.model.Author;

import java.util.List;

@ApplicationScoped
public class AuthorService {

    public Uni<List<Author>> getAllAuthors() {
        return Author.listAll(Sort.by("surname"));
    }

    public Uni<Response> getAuthorById(Long id) {
        return Author.findById(id)
                .onItem().ifNotNull().transform(author -> Response.ok(author).build())
                .onItem().ifNull().continueWith(() -> Response.status(Response.Status.NOT_FOUND).build());
    }

    public Uni<Author> findIfAuthorExists(Author author) {
        return Author.find("name = ?1 and surname = ?2 and dateOfBirth = ?3",
                           author.getName(), author.getSurname(), author.getDateOfBirth())
                .firstResult();
    }

    public Uni<Author> addAuthor(Author author) {
        return findIfAuthorExists(author)
                .onItem().ifNotNull().transform(existingAuthor -> existingAuthor)
                .onItem().ifNull().switchTo(() -> Panache.withTransaction(author::persist).replaceWith(author));
    }

    public Uni<Response> updateAuthor(Long id, Author updatedAuthor) {
        return Author.<Author>findById(id)
                .onItem().ifNotNull().transformToUni(existingAuthor -> {
                    existingAuthor.setName(updatedAuthor.getName());
                    existingAuthor.setSurname(updatedAuthor.getSurname());
                    existingAuthor.setDateOfBirth(updatedAuthor.getDateOfBirth());

                    return Panache.withTransaction(existingAuthor::persist)
                            .replaceWith(Response.ok(existingAuthor).build());
                })
                .onItem().ifNull().continueWith(Response.status(Response.Status.NOT_FOUND).build());
    }

    public Uni<Response> deleteAuthor(Long id) {
        return Panache.withTransaction(() -> Author.deleteById(id))
                .map(deleted -> deleted
                        ? Response.ok().status(Response.Status.NO_CONTENT).build()
                        : Response.ok().status(Response.Status.NOT_FOUND).build());
    }

}

Is it better to just test the resource and leave the service methods alone? The code for this project is available on my Github

I tried using this solution but every test passes, even if I compare 2 to 3;

Upvotes: 0

Views: 206

Answers (1)

Davide D&#39;Alto
Davide D&#39;Alto

Reputation: 8236

I've changed a couple of things and now the test seems to work:

  1. Upgrade Quarkus to 3.14.2. In the pom.xml:

        <properties>
         ...
         <quarkus.platform.version>3.14.2</quarkus.platform.version>
         ...
     </properties>
    
     <dependencies>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-hibernate-reactive-panache</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-rest</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-reactive-pg-client</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-rest-jackson</artifactId>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-junit5</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>io.rest-assured</groupId>
             <artifactId>rest-assured</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>
             <artifactId>lombok</artifactId>
             <version>1.18.34</version>
             <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-test-vertx</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>io.quarkus</groupId>
             <artifactId>quarkus-test-hibernate-reactive-panache</artifactId>
             <scope>test</scope>
         </dependency>
     </dependencies>
     ...
    
  2. Remove quarkus-reactive/src/test/java/um/feri/TransactionalUniAsserterInterceptor.java and update the test to:

    package um.feri.services;
    import java.time.LocalDate;
    
    import org.junit.jupiter.api.Test;
    
    import io.quarkus.test.hibernate.reactive.panache.TransactionalUniAsserter;
    import io.quarkus.test.junit.QuarkusTest;
    import io.quarkus.test.vertx.RunOnVertxContext;
    import jakarta.inject.Inject;
    import um.feri.model.Author;
    
    @QuarkusTest
    class AuthorServiceTest {
    
        @Test
        @RunOnVertxContext
        public void testGetAllAuthors(TransactionalUniAsserter a) {
             a.execute( () -> new Author( "J.K.", "Rowling", LocalDate.of( 1965, 7, 31 ) ).persist() );
    
             // Panache doesn't support  method reference
             a.assertEquals( () -> Author.count(), 6L );
             a.execute( () -> Author.deleteAll() );
        }
    }
    
  3. Optional, add quarkus.hibernate-orm.log.sql=true in the application.properties. It will show you the SQL getting executed.

You should be able to test services the same way, for example:

    @Inject
    AuthorService service;

    @Test
    @RunOnVertxContext
    @Order( 1 )
    public void testGetAllAuthors(TransactionalUniAsserter a) {
        a.execute( () -> new Author( "J.K.", "Rowling", LocalDate.of( 1965, 7, 31 ) ).persist() );
        a.assertEquals( () -> Author.count(), 6L );
    }

    @Test
    @RunOnVertxContext
    @Order( 2 )
    public void testService(TransactionalUniAsserter a) {
        a.assertThat( () -> service.getAllAuthors(), authors -> {
            Assertions.assertNotNull( authors );
            Assertions.assertEquals( 6, authors.size() );
        } );
    }

Upvotes: 0

Related Questions