0

I'm learning Spring: I've a simple JUnit test based on Spring, but I can't understand why one test is failing and the other not, since I'm expecting the @Autowired annotation to work in both of them

I have 2 classes:

package it.euphoria.data.service;

import it.euphoria.data.entity.Customer;
import it.euphoria.data.entity.Seller;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

import javax.validation.constraints.NotNull;
import java.util.Set;

public interface CustomerRepository extends JpaRepository<Customer, Long> {

    @Query("SELECT cust FROM Customer cust WHERE cust.seller = :seller")
    Set<Customer> getBySeller(@NotNull @Param("seller") Seller seller);

}

and a Service class:

package it.euphoria.data.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class CustomerService {

    private CustomerRepository customerRepository;

    @Autowired
    public CustomerService(CustomerRepository customerRepository) {
        this.customerRepository = customerRepository;
    }

    public CustomerRepository getCustomerRepository() {
        return customerRepository;
    }


}

If , while testing, I autowire CustomerRepository it works fine, but if I autowire CustomerService I get an UnsatisfiedDependencyException

This is the working test with CustomerRepository:

package it.euphoria.data.service;

import it.euphoria.data.entity.Customer;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataJpaTest
public class CustomerRepositoryTest {
    @Autowired
    CustomerRepository customerRepository;        

    @Test
    public void getBySeller() {
        //test things...
    }
}

And this is the broken one with CustomerService as only difference:

package it.euphoria.data.service;

import it.euphoria.data.entity.Customer;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@DataJpaTest
public class CustomerRepositoryTest {
    @Autowired
    CustomerService customerService; //<-- The error is here    

    @Test
    public void getBySeller() {
        //test things...
    }
}

This is the stacktrace:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'it.euphoria.data.service.CustomerRepositoryTest': Unsatisfied dependency expressed through field 'customerService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'it.euphoria.data.service.CustomerService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}

I've found this question and answer , but it didn't solve the problem. Could you please help me understanding what I'm doing wrong here?

Leviand
  • 2,745
  • 4
  • 29
  • 43

1 Answers1

1

@DataJpaTest loads the beans which are relevant to the work with the database, read Repositories and more low level stuff (DataSources, Transaction manager, etc).

These tests are used to check the correctness of your SQL queries and any code that resides in the DAO.

It doesn't load the whole application in any case but only a certain part of it.

Now the service is a place where you usually write a business logic and it doesn't interact with database directly (only via DAOs, repositories, etc.)

So spring doesn't load services in @DataJpaTest

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • I didn't know this at all, thanks. So which is the correct annotation to use for make spring load `@Service` classes aswell during testing? – Leviand Jan 25 '21 at 14:46
  • 1
    It depends on the purpose of the test. If you want to load the whole application, use `@SpringBootTest`. If you want to load some part of the application, use `@ContextConfiguration` and specify the configuration to load the classes, this is a broad topic actually... – Mark Bramnik Jan 25 '21 at 14:50