I'm trying to test in SpringBoot application using JUnit some query and I'm getting this error:
NoSuchBeanDefinitionException: No qualifying bean of type DocumentRepositoryTest
#Repository
public interface DocumentRepositoryTest extends DocumentRepository {
#Query("SELECT * " +
"FROM document d" +
"WHERE d.id = :id")
Object runQuery(#NonNull Integer id);
}
#SpringBootTest
public class DocumentServiceTest {
#Autowired
protected DocumentRepositoryTest documentRepositoryTest;
#Test
void testQuery() {
Object o = documentRepositoryTest.runQuery(2);
}
}
I cant understand why I have this issue ?
Make sure that the DocumentRepository is being scanned by Spring component scanning. This can be done by adding the #ComponentScan annotation to your #SpringBootTest class.
Example:
#RunWith(SpringRunner.class)
#SpringBootTest
#ComponentScan(basePackages = "com.example.repository")
public class DocumentServiceTest {
#Autowired
protected DocumentRepositoryTest documentRepositoryTest;
#Test
void testQuery() {
Object o = documentRepositoryTest.runQuery(2);
}
}
Related
I know there are a lot of similar issues here on stackoverflow, but none of this fixes my issue.
I want to expose some methods from my Spring Boot Repositories as Webservice, but one Repository randomly ^(1) only returns 404 on all Methods.
We are talking about following classes
#Component
public class CustomRepositoryRestConfigurer implements RepositoryRestConfigurer {
#Override
public void configureRepositoryRestConfiguration(RepositoryRestConfiguration config, CorsRegistry cors) {
config.disableDefaultExposure();
}
}
#RepositoryRestResource(exported = true)
public interface TransactionRepository extends JpaRepository<Transaction, Long> {
#Query("select t from Transaction where ....")
#RestResource(exported = true) // true is default
Page<Transaction> findAllByQuery(
// more stuff
#Param("text") String text,
Pageable pageable);
void delete(Transaction entity); // should not be exposed!
}
And following tests will fail:
#AutoConfigureMockMvc
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = Application.class)
public class SampleTest {
#Autowired
private MockMvc mvc;
#Test
public void check_profile_is_ok() throws Exception {
mvc.perform(get("/")
// fails...
.andExpect(jsonPath("$._links.transactions").value(notNullValue()))
}
#Test
public void check_access() throws Exception {
mvc.perform(get("/transactions/search/findAllByQuery")
// fails...
.andExpect(status().isOk());
}
}
When remove config.disableDefaultExposure(); the Testcase will pass, but then all Endpoints are exposed - and I don't want this.
Is there any configuration I'm missing?
I have a second repository CategoryRepository and everything is same but working.
Okay I solved it by myself. I had (falsely) a second Repository on the Transaction Entity.
I'm trying to create an integration test for my AssignmentRepository. However the AutoWiring is not working.
Code (AssignmentRepositoryTest):
#ActiveProfiles("test")
#ExtendWith(SpringExtension.class)
#SpringBootTest(classes = RestapiApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class AssignmentRepositoryTest extends ContainerEnvironment {
#Autowired
private AssignmentRepository assignmentRepository;
#Test
public void When_GetAssignments_Expect_EmptyList() {
List<Assignment> list = (List<Assignment>) assignmentRepository.findAll();
assertEquals(0, list.size());
}
}
Code of AssignmentRepository:
#Repository
public interface AssignmentRepository extends CrudRepository<Assignment, Integer> {
List<Assignment> findAllByUserId(#NotNull(message = "No userId given") String userId);
}
I get the following error: java.lang.NullPointerException: Cannot invoke "com.company.restapi.dal.AssignmentRepository.findAll()" because "this.assignmentRepository" is null
I'm using Java with Spring Boot, Spring Boot test & Testcontainers.
Problem description
I have a couple of controllers that look like this:
#RequestMapping("InkUsage")
#RestController
public class InkUsageController extends BaseController<InkUsageDto> {
public InkUsageController(BaseService<InkUsageDto> service) {
super(service);
}
}
#RequestMapping("MediaCategoryUsage")
#RestController
public class MediaCategoryUsageController extends BaseController<MediaCategoryUsageDto> {
public MediaCategoryUsageController(BaseService<MediaCategoryUsageDto> service) {
super(service);
}
}
Both of them extend a BaseController class that looks like this:
#AllArgsConstructor
#RestController
public class BaseController<T> {
private BaseService<T> service;
#PostMapping
public ResponseEntity<List<T>> getAll(){...}
...
}
The BaseService looks like this:
#AllArgsConstructor
#Service
public class BaseService<T> {
private BaseRepository<T> repository;
public List<T> getAll() {...}
...
}
The BaseRepository is just an interface that JpaRepositories extend:
public interface BaseRepository<T> {
List<T> getAllAggregated(String dateFormat);
List<T> getAllNonAggregated(String dateFormat);
...
}
This is how one of the JpaRepositories look like:
#Repository("InkUsageRepository")
public interface InkUsageRepository extends JpaRepository<InkUsageEntity, Long>,
BaseRepository<InkUsageDto> {
#Query("SELECT new api.coloradodashboard.inkusage.InkUsageDto(DATE_FORMAT(i.date, :dateFormat) AS formatted_date, sum(i.cyanLitresUsed), sum(i.magentaLitresUsed), sum(i.yellowLitresUsed), sum(i.blackLitresUsed)) " +
"FROM InkUsageEntity i " +
"GROUP BY formatted_date " +
"ORDER BY formatted_date ASC")
List<InkUsageDto> getAllAggregated(#Param("dateFormat") String dateFormat);
...
}
The problem is that when I run the application Spring complains that BaseService requires a single bean of type BaseRepository but it found 2, which is true. However, both implementations use a different class as a generic type(one uses BaseRepository<InkUsageDto>, for example) and it seems Spring can not pick up that.
Question
How can I tell Spring to use the proper repository?
What I already tried
Spring suggests using a #Primary qualifier, but that will not solve my problem because I plan on having 5 JpaRepositories extending BaseRepository.
I tried passing the repository into the BaseController constructor, then immediately create new BaseService(repository) in the BaseController constructor but Spring complains it can not find a bean of type BaseRepository.
I checked whether passing a variable into a #Qualifier is possible, but they only take constant expressions.
A solution that will probably work but I avoid is to create BaseRepository class implementation for each repository, but that means having 5 implementations with the same code except the repository field.
Edit
I found this article but not sure whether it can help me.
Alright, I found a solution. First, I need to create a BaseServiceFactory and pass the repository to the BaseService constructor:
#NoArgsConstructor
#Service
public class BaseServiceFactory<T> {
public BaseService<T> getBaseService(BaseRepository<T> repository) {
return new BaseService<T>(repository);
}
}
Then each new controller(that inherits BaseController) will invoke the factory and pass the repository explicitly(for example, pass InkUsageRepository or MediaCategoryUsageRepository, etc):
#RequestMapping("InkUsage")
#RestController
public class InkUsageController extends BaseController<InkUsageDto> {
public InkUsageController(BaseServiceFactory<InkUsageDto> baseServiceFactory,
InkUsageRepository repository) {
super(baseServiceFactory.getBaseService(repository));
}
}
And last, the BaseService needs to inject the repository lazily like this:
#Service
public class BaseService<T> {
private final BaseRepository<T> repository;
public BaseService(#Lazy #Autowired BaseRepository<T> repository) {
this.repository = repository;
}
...
}
Well, I think your solution is overcomplicated. I assume you have a Parent class (let's call it BaseEntity) for both InkUsageEntity and MediaCategoryUsageEntity. Just simply do this:
public interface BaseRepository<T extends BaseEntity> extends JpaRepository<T, Long> {
List<T> getAllAggregated(String dateFormat);
List<T> getAllNonAggregated(String dateFormat);
...
}
For these child entites you can have:
public interface InkUsageRepository extends BaseRepository<InkUsageEntity> {
#Query("SELECT new api.coloradodashboard.inkusage.InkUsageDto(DATE_FORMAT(i.date, :dateFormat) AS formatted_date, sum(i.cyanLitresUsed), sum(i.magentaLitresUsed), sum(i.yellowLitresUsed), sum(i.blackLitresUsed)) " +
"FROM InkUsageEntity i " +
"GROUP BY formatted_date " +
"ORDER BY formatted_date ASC")
List<InkUsageDto> getAllAggregated(#Param("dateFormat") String dateFormat);
}
I have a problem of running my Test class. It returns "org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 't.c.i.s.se.Sfts' available: expected single matching bean but found 2: sftsImpl,sfts" this exception after I run it.
Here's my test class;
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Sfta.class)
public class SftaTests {
#Autowired
ApplicationContext ac;
#Test
public void contextLoads() {
Sfts sfts= ac.getBean(Sfts.class);
assertTrue(Sfts instanceof SftsImpl);
}
}
And my other classes are like;
public interface Sfts {
public void process();
}
#Service
#Component
public class SftsImpl implements Sfts {
#Autowired
private GlobalConfig globalConfig;
#Autowired
private Ftr ftr;
private Fc fc;
#Async
#Scheduled(initialDelayString = "${s.f.t.m}", fixedRateString = "${s.f.t.m}")
public void process() {
int hod = DateTime.now().getHourOfDay();
if (hod != 6){
fc = new Fc(globalConfig, ftr);
fc.control();
}
}
}
Why I get the error after running the test application?
Try to remove #Component annotation from the SftsImpl bean.
#Service is enough to register a bean.
Also if you just want to test your bean - getting it from ApplicationContext maybe is not the best option.
Code example of a unit test without using ApplicationContext:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Sfta.class)
public class SftaTests {
#Autowired
Sfts sfts;
#Test
public void testAsync() {
sfts.process();
// do assertions here
}
}
I have a service which I want to test:
public class DepartmentServiceImpl implements DepartmentService {
#Autowired
private DepartmentDao departmentDao;
//... other functions
#Override
public Department getDepartment(int depid) {
return departmentDao.getDepartment(depid);
}
}
and here is my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:sdnext-servlet.xml")
public class TestDepartmentDetails {
Department department = new Department();
DepartmentServiceImpl service = new DepartmentServiceImpl();
#Autowired
private DepartmentDao myDao;
#Test
public void testGetDepartment(){
assertEquals("lalalalalalala", service.getDepartment(98).getDepName());
}
Why it gives me a failure and throws a NullPointerException? Is there any other solution?
Note: This is an application which uses Spring and Hibernate.
Try it this way
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:sdnext-servlet.xml")
public class TestDepartmentDetails {
#Autowired
DepartmentService service;
#Test
public void testGetDepartment(){
assertEquals("lalalalalalala", service.getDepartment(98).getDepName());
}
Here you are creating instances manually which is not the right way while using Spring.
Please refer to the Spring docs below:
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/
You have to autowire DepartmentServiceImpl service instead of DepartmentDao in this case.