1

I have this basic CRUD API using springboot version 2.7.10 and JOOQ 3.14 and it has some previously written tests but they are not working, since i don't have experience with JOOQ and tesccontainer i can't pinpoint what is the problem but i will show the code for reproducing the error which is org.springframework.beans.factory.UnsatisfiedDependencyException

First i have this model class (unfortunately i can't use lombok):

package com.data.platform.core.models;

import java.util.Date;
import java.util.UUID;

public class Owner {
    private UUID ownerId;
    private String ownerName;
    private String ownerEmail;
    private Date updatedAt;
    private Date createdAt;

    public Owner() {
    }

    public Owner(UUID ownerId, String ownerName, String ownerEmail, Date updatedAt, Date createdAt) {
        this.ownerId = ownerId;
        this.ownerName = ownerName;
        this.ownerEmail = ownerEmail;
        this.updatedAt = updatedAt;
        this.createdAt = createdAt;
    }

    public UUID getOwnerId() {
        return ownerId;
    }

    public void setOwnerId(UUID ownerId) {
        this.ownerId = ownerId;
    }

    public String getOwnerName() {
        return ownerName;
    }

    public void setOwnerName(String ownerName) {
        this.ownerName = ownerName;
    }

    public String getOwnerEmail() {
        return ownerEmail;
    }

    public void setOwnerEmail(String ownerEmail) {
        this.ownerEmail = ownerEmail;
    }

    public Date getUpdatedAt() {
        return updatedAt;
    }

    public void setUpdatedAt(Date updatedAt) {
        this.updatedAt = updatedAt;
    }

    public Date getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
        this.createdAt = createdAt;
    }
}

Then i have this repository class:

package com.data.platform.core.repository.impl;

import com.data.platform.core.dto.requests.OwnerDtoRequest;
import com.data.platform.core.entity.operation.tables.Owners;
import com.data.platform.core.models.Owner;
import com.data.platform.core.converters.OwnerConverter;
import com.data.platform.core.Repository.OwnerRepository;
import org.jooq.DSLContext;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Optional;
import java.util.UUID;

@Repository
public class OwnerRepositoryImpl implements OwnerRepository {
    
    @Autowired
    private DSLContext dslContext;

    @Autowired
    private OwnerConverter ownerConverter;

    @Override
    public List<Owner> findAll(Integer size, Integer offset) {

        return dslContext.selectFrom(Owners.OWNERS)
                .limit(size)
                .offset(offset)
                .fetch(ownerConverter);
    }

    @Override
    public Optional<Owner> findById(UUID ownerId) {

        return dslContext.selectFrom(Owners.OWNERS)
                .where(Owners.OWNERS.OWNER_ID.eq(ownerId))
                .fetch().map(ownerConverter).stream().findFirst();
    }

    @Override
    public Owner insert(OwnerDtoRequest owner) {

        return dslContext.insertInto(Owners.OWNERS)
                .set(Owners.OWNERS.OWNER_NAME, owner.getOwnerName())
                .set(Owners.OWNERS.OWNER_EMAIL, owner.getOwnerEmail())
                .returning()
                .fetchOne()
                .map(ownerConverter);
    }

    @Override
    public Owner update(UUID ownerId, OwnerDtoRequest owner) {

        return dslContext.update(Owners.OWNERS)
                .set(Owners.OWNERS.OWNER_NAME, owner.getOwnerName())
                .set(Owners.OWNERS.OWNER_EMAIL, owner.getOwnerEmail())
                .where(Owners.OWNERS.OWNER_ID.eq(ownerId))
                .returning()
                .fetchOne()
                .map(ownerConverter);
    }

    @Override
    public Integer delete(UUID ownerId) {

        return dslContext.delete(Owners.OWNERS)
                .where(Owners.OWNERS.OWNER_ID.eq(ownerId))
                .execute();
    }
}

The converter is just a component to transform record into model:

package com.data.platform.core.converters;

import com.data.platform.core.entity.operation.tables.records.OwnersRecord;
import com.data.platform.core.models.Owner;
import org.jetbrains.annotations.Nullable;
import org.jooq.Record;
import org.jooq.RecordMapper;
import org.springframework.stereotype.Component;

import java.time.ZoneId;
import java.util.Date;
import java.util.Objects;
import java.util.function.Function;

@Component
public class OwnerConverter implements Function<OwnersRecord, Owner>, RecordMapper<Record, Owner> {
    /**
     * Applies this function to the given argument.
     *
     * @param ownersRecord the function argument
     * @return the function result
     */
    @Override
    public Owner apply(OwnersRecord ownersRecord) {
        return new Owner(ownersRecord.getOwnerId(), ownersRecord.getOwnerName(), ownersRecord.getOwnerEmail(), createdAtDate, updateAtDate);
    }

    /**
     * Map a r into a POJO.
     *
     * @param r The record to be mapped. This is never null.
     * @return The mapped value, which may be <code>null</code> in some
     * implementations.
     */
    @Override
    public @Nullable Owner map(Record r) {
        return apply((OwnersRecord) r);
    }
}

Now for the test part which i am having trouble, first of there is this abstract class which supposedly would create a test container and create an instance of DSLContext so we can test the repository, if i remove @SpringBootApplication(exclude = {R2dbcAutoConfiguration.class}) the org.springframework.beans.factory.UnsatisfiedDependencyException occurs on the abstract class:

package com.data.platform.core.repository.common;

import org.jooq.DSLContext;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jooq.JooqAutoConfiguration;
import org.springframework.boot.autoconfigure.r2dbc.R2dbcAutoConfiguration;
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Import;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
import org.testcontainers.containers.PostgreSQLContainer;

import static com.data.platform.core.entity.operation.tables.Owners.OWNERS;


@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = BaseRepositoryTest.Initializer.class)
@SpringBootApplication(exclude = {R2dbcAutoConfiguration.class})
public abstract class BaseRepositoryTest {
    public static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>("postgres")
            .withDatabaseName("data-platform")
            .withUsername("postgres")
            .withPassword("password");

    @Autowired
    DSLContext dslContext;

    static {
        postgres.start();
    }

    static class Initializer
            implements ApplicationContextInitializer<ConfigurableApplicationContext> {
        public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
            TestPropertyValues.of(
                            "spring.datasource.url=" + postgres.getJdbcUrl(),
                            "spring.datasource.username=" + postgres.getUsername(),
                            "spring.datasource.password=" + postgres.getPassword()
                    )
                    .applyTo(configurableApplicationContext.getEnvironment());
        }
    }


    public void cleanUpAll() {
        // There are more clean ups
        ownerCleanUp();
    }


    void ownerCleanUp() {
        dslContext.deleteFrom(OWNERS)
                .execute();
    }

}

And there is the respective OwnerRepositoryTest class which extends from the BaseRepository so theoretically it would have the dslContext, but for some reason gives me the following error org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.bees.data.platform.core.repository.OwnerRepositoryTest': Unsatisfied dependency expressed through field 'dslContext'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'org.jooq.DSLContext' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}:

package com.data.platform.core.repository;

import com.data.platform.core.converters.OwnerConverter;
import com.data.platform.core.repository.common.BaseRepositoryTest;
import com.data.platform.core.entity.operation.tables.records.DomainsRecord;
import com.data.platform.core.models.Owner;
import org.jooq.Result;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

import static com.data.platform.core.repository.fixtures.OwnerRepositoryTestFixture.defaultListOfOwners;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

public class OwnerRepositoryTest extends BaseRepositoryTest {

    @Autowired
    OwnerRepository ownerRepository;

    @Autowired
    OwnerConverter ownerConverter;

    @Test
    public void testFindAll() {
        // Arrange
        Integer size = 10;
        Integer offset = 0;

        List<Owner> expectedOwners = defaultListOfOwners();

        // Act
        List<Owner> actualOwners = ownerRepository.findAll(size, offset);

        // Assert
        assertThat(expectedOwners, is(equalTo(actualOwners)));
    }
}

Again, as i don't have much experience with JOOQ i couldn't find the problem or if there is a better way to implement this kind of test, any kind of help would be appreciated.

1 Answers1

0

I think that exclude is added on purpose and you can't remove it.

@SpringBootApplication(exclude = {R2dbcAutoConfiguration.class})

Ensure if you are facing problem mentioned in this old post. This might help you. jooq-dslcontex

Vishal
  • 34
  • 7
  • 1
    Hello, i've read the question and made some changes in my test code which changed the exception, i've added `@Import({DataSourceAutoConfiguration.class, TransactionAutoConfiguration.class, JooqAutoConfiguration.class}` and i got the following error: – Paulo Henrique Jun 18 '23 at 22:41
  • 1
    `org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'com.data.platform.core.repository.OwnerRepositoryTest': Unsatisfied dependency expressed through field 'ownerRepository'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.data.platform.core.repository.OwnerRepository' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}` – Paulo Henrique Jun 18 '23 at 22:42
  • If you are writing unit test cases for OwnerRepository then you should mock this repository and also ensure that all those class references marked `@Autowired` have a annotations like `@Service` or `@Repository` depending on the role. – Vishal Jun 25 '23 at 08:32