I'm learning tests and I consider situation when i have class like that:
#Service
#RequiredArgsConstructor
#Transactional(readOnly = true)
public class SearchCustomerService {
private final CustomerRepository CustomerRepository;
public Page<CustomerDTO> search(CustomerCriteria criteria, Pageable pageable) {
CustomerSpecification specification = new CustomerSpecification(criteria);
return customerRepository.findCustomers(specification, pageable);
}
}
How tests should looks like? I think unit tests are not that really good because what am I actually testing? I'm just getting some data from database and if I mock repository.. then I test Mockito, right?
You can create integration test that includes persistence layer (eg inmemory H2), service and meaningfull dependencies, where your input would be a proper set of Customer entities in the repository, and assert outcome of invoking search based on some criterias.
To make it a unit test, I can you could only assert the shape of CustomerSpecification but that will not guarantee that specs itself are valid for given case - thus makes small sense.
This case is similar to testing native queries execution. You don't assert SQL string, but assert result having test data set.
Related
I have a Spring Boot project and I want to test some queries. I want to insert a predefined set of data and execute the Repository query to check the result is the desired one.
To do this I'm using in-memory H2 DB and the problem (I think) is not there, everything related with DB is ok. The main problem is I can't mock properly the EntityManager field in repository and the query is always null.
My repository is like this:
#Repository
public class MyRepositoryImpl implements MyRepository {
#PersistenceContext
private EntityManager entityManager;
#Override
public Result runQuery() {
TypedQuery<Result> query = entityManager.createQuery(
"SELECT ...", Result.class);
return query.setParameter("...", "...") // here 'query' is always null
.setMaxResults(1)
.getResultStream()
.findFirst()
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Entity not found"));
}
}
It works nice when is executed out of tests, but trying to run this test file it throw an error:
#RunWith(SpringRunner.class)
public class MyRepositoryTest {
#Mock
EntityManager entityManager;
#InjectMocks
MyRepositoryImpl repository;
#Test
public void it_should_works() {
Result r = repository.runQuery();
assertNull(r);
}
}
The repository is mocked and is not null, I can call the method. But inside the repository, as query field is null, it throw a NullPointerException when try to execute.
I've searched over the internet and I've found many ways to test the JPARepository and #Query inside the interface, but not an EntityManager query.
Also I've found a few ways to mock the result for the query, something like when(runQuery()).thenReturn(result) but I don't want that, I've the data in the memory DB so I want to execute the query and get the result.
So, now, the main problem I think is how to mock the EntityManager object properly inside repository class.
Thanks in advance.
Edit:
I've follow this link and is like another SO questions: It's only to mock the JpaRepository.
I've used this code:
#Test
public void it_should_works() {
Result r = repository.findAll();
assertNotNull(r);
}
And works perfectly, but using my own query fails with error:
org.springframework.orm.jpa.JpaSystemException: could not advance using next(); nested exception is org.hibernate.exception.GenericJDBCException: could not advance using next()
...
Caused by: org.h2.jdbc.JdbcSQLNonTransientException: El objeto ya está cerrado
The object is already closed [90007-200]
So the question is: It is related to my DB? Why using JpaRepository method it works but my own query don't?
Edit:
Solved adding #Transactional into repository.
Since you're using an h2 in-memory database to run tests, and you want to actually use that database in your tests, you shouldn't really be mocking anything.
Your mocking doesn't work because the MyRepositoryImpl is typically initialized by Spring, and that process is much more complicated than plugging in an EntityManager.
I think what you want to do is more like what's described here https://www.baeldung.com/spring-testing-separate-data-source
So you would have a src/test/resources/application.properties file that overrides the datasource properties. Then you just #Autowired your repository into your test class like normal.
I have simple crud repository:
public interface BookRepository extends CrudRepository<Book, Long> {
#Modifying
#Transactional
void deleteById(Long id);
}
How can I write simple JUnit test to check if this method works fine? Of course, in this case, I have entity Book
You should not.
Unit testing Spring Data repositories is a problem of Spring Data developers - as a developer you are using their API and it should working that's all. Care about your logic not the library - focus on integration tests
Anyway if you really want to do this - what I would do would be to mock EntityManager and somehow inject it to the Repository implementation (sounds like horrible task), or I would use DBUnit test, prepare test data and simply would check whether object was deleted (this would be prefered way)
Usually Spring Data repositories do not tests, but If you really want to test it you can use #DataJpaTest and inject TestEntityManager.
Example:
#DataJpaTest
class BookRepositoryTest {
#Autowired
private BookRepository repository;
#Autowired
private TestEntityManager em;
#Test
void deleteById() {
Book book = ...;
final Long id = em.persistAndGetId(book, Long.class);
repository.deleteById(id);
em.flush();
Book after = em.find(Book.class, id);
assertThat(after).isNull();
}
}
Idea is that you use TestEntityManager for all operation exclude your. In the example you are persist and find entity via TestEntityManager but delete via your custom repository.
I'm using hibernate with critera builing queries and specification pattern.
My interface:
public interface Specification<T> {
Criterion toCriteria();
}
Implementations looks like:
Restrictions.eq("someField", "value");
My goal is to test that my enity class has "someField" with exact name.
At this time i have hibernate integration test and it covers problem at some point, but obviously unit-test for reflection fields should be separeted.
I will be grateful for the suggestions on the solution.
How can I test HQL query with JUnit tests?
I have mapped Entity Class:
#Entity
#Table(name = "DOE")
public DomainObjectEntity {
//some attributes
}
which represents domain objects:
public class DomainObject {
//some attributes
}
I also have repository interface for my domain objects:
public interface DomainObjectRepository {
/**
* Gets entity by some attribute
*
*/
DomainObject getDomainObjectByObjectId(String objectId);
}
this interface is implemented in
#Repository
public class DomainObjectRepositoryImpl implements DomainObjectRepository {
#Inject
private DomainObjectEntityJPARepository entityRepository;
#Override
public DomainObjectgetDomainObjectById(String parcelId) {
//this converts my entity to domain object
return entityRepository.findByDomainObjectId(DomainObjectId.getStr()).getDomainObject();
}
}
my JPA Entity repository looks like this:
public interface DomainObjectEntityJPARepository extends JpaRepository<DomainObjectEntity, String> {
/**
* get DomainObject with requested id
*
* #param objectId - objects id
* #return DomainObject
*/
#Query("some query to be tested")
DomainObjectEntity findByDomainObjectId(#Param("objectId") String objectId);
}
and finally i want to write a simple JUnit test to check if query to findByDomainObjectId returns the correct object. I think my test should look like this:
create object to put into DB
retrieve object from DB
compare objects
How can I write such test?
Any good examples of testing HQL query with junit and repositories?
if you want to test, if your method returns the correct object, just mock your entitymanager or whatever you use for querying your DB using mockito.
If you want to test if your query works, you should setup a test DB (a in memory DB is used in this case most of the time) with the same schema and simple test data already in the DB. In your test method you should only call the method with a known id and check if you get the correct object. H2 is simple to use for in-memory testing and you can use your create.sql script (if you have one) and an insert.sql script, where you define your known test data.
It is an important aspect of unit testing to only test one part of your program at a time. if you would insert into the DB in your test you would also test the insert aspect and not only the read aspect.
You just have to use a test db, like H2 which is a in memory db, and then use Junit to see the returned entity.
I've just started integrating QueryDSL into a Spring Boot project and I'm looking for a way to build a query out of an existing entity bean. Using #ModelAttribute it's nice and easy to pass in an entity via a GET request from the controller as long as the parameters align with the bean:
public Page<Company> getLogins(#ModelAttribute Company company, Pageable pageable, #RequestParam(value = "page", required = false) String pageNumber){
return companyService.findbyParameters(company,pageNumber);
}
And in the service class, I can use the BooleanBuilder to build up a query:
public Page<Company> findbyParameters(Company companySearch,String pageNumber){
QCompany company = QCompany.company;
BooleanBuilder builder = new BooleanBuilder();
if (companySearch.getEmail() != null && !companySearch.getEmail().equals("")){
builder.and(company.email.eq(companySearch.getEmail()));
}
if (companySearch.getCompanyName() != null && !companySearch.getCompanyName().equals("")){
builder.and(company.companyName.eq(companySearch.getCompanyName()));
}
//add other clauses...
return loginRepository.findAll(builder.getValue(),pageableService.getPageRequest(pageNumber));
}
..and this works fine. But it seems like an unnecessary amount of plumbing since I'll have to write similar, longwinded conditional code for each entity I'm working with. I reckon that reflection might be an option, but I'm not sure if QueryDSL has something built in that handles this situation. I've looked at the QueryDSL docs and nothing jumped out at me.
So is there a nice, tidy way of handling this situation without clogging up my service classes with boilerplate?
You can use Spring Data's QueryDSL integration. Basically, you extend the QueryDslPredicateExecutor in your repository interface and it add a findAll method that gets a QueryDSL Predicate and filter all the results based on that Predicate. You see more details here.
It turns out that the exact thing I was looking for is Spring Data's query by example API.
https://www.baeldung.com/spring-data-query-by-example
It lets you create a query by providing a sample entity and a matcher which defines things like case sensitivity, partial 'like' matching and so on.
It's very useful in limited situations, and can drastically reduce boilerplate query code; but when you want to query a more complex graph of data you'll want to use a different approach.