How to test JPA Specification - java

I have a builder that create a JPA Specification according to filters. How do I test the builder ? assertEquals method always return false when comparing Specifications...
I already try to call Specification::toPredicate method with mock args but the returned value is null. I would like to avoid loading the entityManager.
Specification<MyClass> nullSpecification = Specification.where(null);
Specification<MyClass> nullSpecification2 = Specification.where(null);
assertEquals(nullSpecification, nullSpecification2);
I expected assertEquals(nullSpecification, nullSpecification2) to return true but the actual value is false. How can I compare JPA Specification ?

I see the following options.
Bite the bullet and create an integration test, i.e. create an EntityManager and run queries against an in memory database or Testcontainers.
Inspect the internals of the generated Predicate by passing in carefully configured mocks and then using type checking, reflection and knowledge of internals of your JPA provider to assert that you'll get the right predicate.
The problem with the 2nd approach is that it is very brittle and is likely to break although the Specification is actually fine.
I therefore would go with option 1 although I'd prefer a unit test as well.

Related

Unit test for a large SELECT query with jOOQ

I am using jOOQ for working with a relational database. I have a SELECT query for which I need to write unit tests with mocking. Based on this doc and this post, I need to define my own data provider, which should look something like this:
class MyProvider implements MockDataProvider {
DSLContext create = DSL.using(SQLDialect.MYSQL);
#Override
public MockResult[] execute(MockExecuteContext mockExecuteContext) throws SQLException {
MockResult[] mock = new MockResult[1];
String sql = mockExecuteContext.sql();
if (sql.startsWith("select")) {
Result<Record2<String, String>> result = create.newResult(COL_1, COL_2);
result.add(create.newRecord(COL_1, COL_2)
.values("val1", "val2"));
mock[0] = new MockResult(1, result);
}
return mock;
}
}
where COL_1 and COL_2 are defined as follows:
Field<String> COL_1 = field("Column1", String.class);
Field<String> COL_2 = field("Column2", String.class);
It's quite simple and straightforward when SELECT is a small one (as in the above example, just 2 columns). I am wondering how it should be done in case of complex and large selects. For instance I have a SELECT statement which selects 30+ columns from multiple table joins. Seems the same approach of
Result<Record_X<String, ...>> result = create.newResult(COL_1, ...);
result.add(create.newRecord(COL_1, ...)
.values("val1", ...));
does not work in case of more than 22 columns.
Any help is appreciated.
Answering your question
There is no such limitation as a maximum of 22 columns. As documented here:
Higher-degree records
jOOQ chose to explicitly support degrees up to 22 to match Scala's typesafe tuple, function and product support. Unlike Scala, however, jOOQ also supports higher degrees without the additional typesafety.
You can still construct a record with more than 22 fields using DSLContext.newRecord(Field...). Now, there is no values(Object...) method on the Record type, because the Record type is the super type of all the Record1 - Record22 types. If such an overload were present, then the type safety on the sub types would be lost, because the values(Object...) method is applicable for all types of arguments. This might be fixed in the future by introducing a new RecordN subtype.
But you can load data into your record with other means, e.g. by calling Record.fromArray(Object...):
Record record = create.newRecord(COL_1, ...);
record.fromArray("val1", ...);
result.add(record);
The values() method being mere convenience (adding type safety) for fromArray().
Disclaimer:
I'm assuming you read the disclaimer on the documentation page you've linked. I'm posting it here anyway for other readers of this question, who might not have read the disclaimer:
Disclaimer: The general idea of mocking a JDBC connection with this jOOQ API is to provide quick workarounds, injection points, etc. using a very simple JDBC abstraction. It is NOT RECOMMENDED to emulate an entire database (including complex state transitions, transactions, locking, etc.) using this mock API. Once you have this requirement, please consider using an actual database instead for integration testing, rather than implementing your test database inside of a MockDataProvider.
It seems you're about to re-implement a database which can "run" any type of query, including a query with 23+ columns, and every time you change the query under test, you will also change this test here. I still recommend you do integration testing instead, using testcontainers or even with H2, which will help cover many more queries than any such unit test approach. Here's a quick example showing how to do that: https://github.com/jOOQ/jOOQ/tree/main/jOOQ-examples/jOOQ-testcontainers-example
Also, integration tests will help test query correctness. Unit tests like these will only provide dummy results, irrespective of the actual query. It is likely that such mocks can be implemented much more easily on a higher level than the SQL level, i.e. by mocking the DAO, or repository, or whatever methods, instead.

jUnit how to test methods that only set data from entity to dto

I've problems with test methods which only get data from entity and assign it to DTO.
I passed empty DTO, and entity created by entityMother. The method works correctly, but I don't know how to make assertion for this. I think that creating assertion for each value/property of this DTO is not a right way to test it.
Why I need to test methods like this?
The methods that set data from entity to DTO has small formatting specyfic fields. Like splitting a string etc.
#Test
public void shouldSetAvailabilities() {
EditedTemplateShowDto editedTemplateDto = new EditedTemplateShowDto();
productTemplateEditService.getAndSetAvailabilities(editedTemplateDto, editedProduct);
//Here should be condition which check that the metod set data
}
I just need to check that the method didn't throw any errors, and none of fields has assigned null value.
The possible solutions are:
You may serialize your objects to JSON then compare the resulting strings. (Cleanest way)
Overriding a matching toString() then compare the resulting strings.
Put several assert condition using reflection (to check the variable name) in a test to check there are no any null value or not mapped value (Bad Practice).
Why I need to test methods like this?
First of all, you don't need to test anything. If you feel the code is extremely straight forward then I would advice to just invest your time into something else. Or perhaps write one sweeping test so at least you have code coverage (but IMO you'd be doing this more for the stats than actual quality of your product).
I just need to check that the method didn't throw any errors
That's easy! Just write a unit test that calls the method. If the method throws any exceptions, the test will fail. If you want to make your test method more intent-revealing, you could explicitly write it like:
try {
productTemplateEditService.getAndSetAvailabilities(editedTemplateDto, editedProduct);
} catch(Exception e) {
fail("Should not have thrown any exception");
}
But again, I'd only do this with methods I expect to throw exceptions (e.g. because they have exception paths or use other code/libraries that may throw exceptions). The default behavior of any unit test is to fail when it encounters an uncaught exception.
none of fields has assigned null value.
The JUnit way is to use assertNotNull in your test method on any fields you want to ensure are not null.
If you want a more generic approach there are additional libraries like assertj's hasNoNullFieldsOrProperties.
assertThat(editedTemplateDto).hasNoNullFieldsOrProperties();
Or you could write your own code using reflection like:
for (Field f : editedTemplateDto.getClass().getDeclaredFields())
assertNotNull(f.get(editedTemplateDto))
But I'd advice against this as it makes your test code harder to understand (and possibly brittle because reflection itself can be tricky)
The methods that set data from entity to DTO has small formatting
specyfic fields. Like splitting a string etc.
This makes a unit test meaningful: verify if the fields in the DTO are filled as expected. So don't just test on notNull but test on
Assert.assertEquals("FieldX has a wrong value","myexpectedValue",dto.getFieldX());
This way you test if the split logic behaves as expected.
Also test it with null values in all optional fields to verify you don't get NullPointerException.

Is JpaRepository's findAll() guaranteed to return a non-null result if an exception isn't thrown?

The documentation is woefully sparse on this point.
This is documented, see section Null Handling of Repository Methods of the Spring Data JPA documentation:
Repository methods returning collections, collection alternatives,
wrappers, and streams are guaranteed never to return null but rather
the corresponding empty representation. See “Repository query return
types” for details.
As Spring Data JPA generates the query methods based on naming patterns and JpaRepository is only one example of such repositories, it probably didn't make sense to document it in the JavaDoc, but instead they put it in the user documentation.
Well, the Package summary of org.springframework.data.repository says Non-Null APIS. That means that it is guaranteed to return non-null type of objects from the method.
#NonNullAPI tells that package with this annotation is null-safe and API usage need not look into handling the null-check scenario.

Unit testing a method with easymock

So I have the bellow method which I want to perform a unit test on.
public List<Project> getProjects(Task task) {
Criteria<Project> criteria = this.myRepository.getCriteria(Project.class);
criteria.add(Comparison.eq("order", task.getOrder()));
criteria.addOrder(Order.asc("projectNumber"));
return this.myRepository.findList(Project.class, criteria);
}
So it actually gets the task object(It is a JPA model object) and goes throw the project table and finds all the projects which have this project's orders. Order is common in both tables.
Anyways, query itself is not that imp. It queries db and returns some data. Now my problem how can I perform a unit test on this with easymock?
#Test
public void testGetProjects() throws Exception {
myRepository = new CreateMyRepositoryWrapper(); --> This is a class which just returns the entityManger. but here we can consider this as a pojo.
Task task = EasyMock.createNiceMock(Task.class);
Order bom = EasyMock.createNiceMock(Order.class);
Project project= EasyMock.createNiceMock(Project.class);
project.setProjectName("project"); ------> Can I call a seeter on a mocked object?
project.setProjectNumber("1");
EasyMock.replay(project);
List projects= new ArrayList(Arrays.asList(project));
bom.setProjects(projects); ------------> Does it make sense to do this?
EasyMock.expect(task.getOrders()).andReturn(bom);
TestClass instance = new TestClass();
instance.setMyRepository(myRepository);
EasyMock.replay(task,bom);
instance.getProjects(task);
}
So this passes the test case. But I am not sure with all those mocking what I am actually testing.. Because it just shows that those methods are being called. But since they are mocked I am not sure if I can use assertEquals or not and even if I can I am getting an exception cuz I have to add more to the above code I think.
So my question: For the method mentioned what should be the proper unit test case?
Thanks.
I think you have this mocking backwards. Mock myRepostory, then set up the myRepository mock to return a Criteria object and to return a project list when that Criteria object is passed to findList.
Task, Order and Project can probably just be instantiated.
Now, instance.getProjects(task) will return something. You can check to make sure that thing that got returned is the same thing you said should be returned from findList. Now you've actually tested something, albeit nothing particularly interesting.
You probably want to validate that the criteria object was set up correctly before it was passed to findList. To do that, you either have to make criteria a mock, then you can set up your expectations for what methods are called. The tricky part here is that Hibernate Restriction classes do not have a non-default equals implementation, so you have to write your own matcher to check that the Restrictions being passed to the criteria are the same (functionally) as the Restrictions you expect.
Another possibility is to set up criteria as an actual Criteria object. (You still set up your myRepository mock to return it.) Then, after the function is called, you can check the contents with some substring matching on the toString() method or any other ways you know to inspect the Criteria object.
A final (unit test) possibility is to not use a mocking framework for the Criteria object, but some hand-coded one that you write that allows you to inspect all of the Restrictions that were added to it.
All of this makes a good case for this method actually being tested with integration testing instead. You wind up doing a lot of work to verify some not very interesting things and your tests can become quite brittle if you try to refactor the code. (I've done it myself, so I speak from experience.)

Java Programming - Spring and JDBCTemplate - Use query, queryForList or queryForRowSet?

My Java (JDK6) project uses Spring and JDBCTemplate for all its database access. We recently upgraded from Spring 2.5 to Spring 3 (RC1). The project does not use an ORM like Hibernate nor EJB.
If I need to read a bunch of records, and do some internal processing with them, it seems like there are several (overloaded) methods: query, queryForList and queryForRowSet
What should be the criteria to use one instead of the other? Are there any performance differences? Best practices?
Can you recommend some external references for further research on this topic?
I find that the standard way to access as list is via the query() methods rather than any of the other approaches. The main difference between query and the other methods is that you'll have to implement one of the callback interfaces (either RowMapper, RowCallbackHandler, or ResultSetExtractor) to handle your result set.
A RowMapper is likely what you'll find yourself using most of the time. It's used when each row of the result set corresponds to one object in your list. You only have to implement a single method mapRow where you populate the type of object that goes in your row and return it. Spring also has a BeanPropertyRowMapper which can populate the objects in a list via matching the bean property names to the column names (NB this class is for convenience not performance).
A RowCallbackHandler is more useful when you need your results to be more than just a simple list. You'll have to manage the return object yourself you are using this approach. I usually find myself using this when I need a map structure as my return type (i.e. for grouped data for a tree table or if I'm creating a custom cache based of the primary key).
A ResultSetExtractor is used when you want to control the iteration of the results. You implment a single method extractData that will be the return value of the call to query. I only find myself using this if I have to build some custom data structure that is more complex to build using either of the other callback interfaces.
The queryForList() methods are valuable in that you don't have to implement these callback methods. There are two ways use queryForList. The first is if you're only querying a single column from the database (for example a list of strings) you can use the versions of the method that takes a Class as an argument to automatically give you a list of only objects of those classes.
When calling the other implementations of queryForList() you'll get a list back with each entry being a map of for each column. While this is nice in that you are saved the expense of writing the callback methods, dealing with this data structure is quite unwieldy. You'll find yourself doing a lot of casting since the map's values are of type Object.
I've actually never seen the queryForRowSet methods used in the wild. This will load the entire result of the query into a CachedRowSet object wapped by a Spring SqlRowSet. I see a big downside in using this object in that if you're passing the SqlRowSet around to the other layers of your application, you're coupling those layers to your data access implementation.
You shouldn't see any huge performance differences between any of these calls except as I mentioned with the BeanPropertyRowMapper. If you're working with some complex manipulation of a large result set, you might be able to get some performance gains from writing an optimized ResultSetExtractor for your specific case.
If you want to learn more I would consult the Spring JDBC documentation and the JavaDoc for the classes I've mentioned. You can also take a look at some of the books on the Spring Framework. Though it's a bit dated Java Development with the Spring Framework has a very good section on working with the JDBC framework. Most of all, I would say just try writing some code with each method and see what works best for you.
Since you are in the wonderful Generics land, what you may really want to do is to use SimpleJdbcTemplate and use its query() methods for Lists of objects and queryForObject() for individual objects. Reasoning for this simply is that they're even easier to use than the ones in JdbcTemplate.
One small addition to the excellent answers above: additional methods, like queryForInt, queryForLong, queryForMap, queryForObject, etc. might seem like good options at times if you're running a simple query and expect a single row.
However, if you could get 0 or 1 rows back, the queryForList method is generally easier, otherwise you'd have to catch IncorrectResultSizeDataAccessException. I learned that the hard way.

Categories