Normally, sometime we need to test some business methods which needs return lots of data from DAO layer, and used Mockito mocks the DAO layer. So we need to prepare the return data from DAO methods. And normally it needs build tons of beans.
Is there any good way to build the data easily without DB(even in memory)?
Example:
when(personDAO.findAll()).then(new Answer<List<Person>>() {
#Override
public List<Person> answer(InvocationOnMock invocation) throws Throwable {
return JSONUtil.parse(file, Person.class);
// ... or ...
Person person1 = new Person(1, "troy");
Person person2 = new Person(2, "linda");
// ... more than 3 person
return Arrays.asList(person1, person2, person....);
}
});
PS: as I can think a way to build a JSON file, serialise the list of beans into file, and before we mock the methods return we deserialise into list of beans.
Related
Given the following service method in a Spring Boot application:
#Transactional
public void updateCategory(long categoryId, CategoryData categoryData) {
final Category category = categoryRepository.findById(categoryId).orElseThrow(EntityNotFoundException::new);
category.setName(categoryData.getName());
}
I know how to instruct Mockito to mock the categoryRepository.findById() result.
However, I couldn't figure out yet: Is it possible to verify that category.setName() was called with the exact argument of categoryData.getName()?
You are looking for Mockito.verify, and a test looking like:
#ExtendWith(MockitoExtension.class)
public class CategoryServiceTest {
#Mock
CategoryRepository categoryRepository;
#InjectMocks
CategoryService categoryService;
#Test
public void testUpdateCategoryMarksEntityDirty() {
// given
long categoryId = 1L;
Category category = mock(Category.class);
String newCategoryName = "NewCategoryName";
when(categoryRepository.findById(categoryId)).thenReturn(Optional.of(category));
// when
categoryService.updateCategory(categoryId, new CategoryData(newCategoryName));
// then
verify(category, times(1)).setName(newCategoryName);
}
}
I must, however, advise against this style of testing.
Your code suggests that you are using a DB Access library with dirty-checking mechanism (JPA / Hibernate?). Your test focuses on the details of interaction with your DB Access layer, instead of business requirement - the update is successfully saved in the DB.
Thus, I would opt for a test against a real db, with following steps:
given: insert a Category into your DB
when: CategoryService.update is called
then: subsequent calls to categoryRepository.findById return updated entity.
How to write a method in myDAOTest class to test my DAOImpl Class using Mockito? here is the method which i need to test from my TestClass.
#Override
public myCustomResponse mymethod(String query, Map<String, Object> parameters) {
jdbcTemplate.query(query, parameters, new ResultSetExtractor<List<MyObject>>() {
#Override
public List<MyObject> extractData(ResultSet result) throws SQLException, DataAccessException {
try {
List<MyObject> myObject= new ArrayList<>();
while (result.next()) {
response = getResponseDetails(result);
}
return myObject;
} catch (SQLException sqlException) {
LOG.debug(MyConstants.DATABASE_EXCEPTION_MESSAGE);
throw new MyCustomeException(MyConstants.DATABASE_EXCEPTION_MESSAGE);
}
}
});
}
return response;
}
Possibility 1:
Extract your ResultSetExtractor into it's own class, which makes it much simpler to test than as an anonymous inner class.
Possibility 2:
Mock the jdbcTemplate, create an ArgumentCaptor, call the method and then do...
Mockito.verify(this.jdbcTemplate).query(any(), any(), captor.capture());
This allows you to then get the ResultSetExtractor from the ArgumentCaptor and run tests on that. But this makes your whole test complex, so I still suggest possibility 1.
Possibility 3:
Test the whole thing against an in-memory database,testing the ResultSetExtractor only indirectly. Since this seems to be Spring, there are easy ways to do so, but of course, your unit test will now include a whole SpringApplicationContext, a db, etc. - which makes it slower than a "pure" unit test with only mocks. Since it's something that fires queries to a db, you will need to run it against a db anyway some time, otherwise your tests will not really be complete (simulating it via mocks is good for the basics, but not the same thing).
For a Spring Framework App, about Testing:
The business layer is working with AssertJ and JUnit.
The web layer is working with JUnit and Spring MVC Test, where the latter works mandatorily with Hamcrest. See Is there a way to use AssertJ assertions with Spring MVC Test? (The answer is no yet)
If in AssertJ is possible apply the following for a collection:
.containsExactly(tuple("087", "Peter", "Jordani", parse("1980-01-01")),
...
tuple("088", "Isaias", "Jordano", parse("1980-01-01")))
What could be the best equivalent approximation of these three methods:
containsExactly
tuple
parse
To be applied in:
.andExpect(model().attribute("personas", ???)
I did a research in google:
about collections there are samples for simple collections (String, Integer with hasItems)
about dates, is working only with Date objects, of course same type, but not with String too.
Please take a look on these tests examples:
public class Test {
private List<Person> personList;
private Person peter = new Person("087", "Peter", parse("1980-01-01"));
private Person john = new Person("081", "John", parse("1980-01-22"));
#BeforeEach
void setup() {
personList = new ArrayList<>();
personList.add(peter);
personList.add(john);
}
#Test
void assertjTest() {
assertThat(personList).extracting("age", "name", "date")
.containsExactly(
tuple("087", "Peter", parse("1980-01-01")),
tuple("081", "John", parse("1980-01-22"))
);
}
#Test
void hamcrestTest() {
org.hamcrest.MatcherAssert.assertThat(personList,
contains(
allOf(
hasProperty("age", is("087")),
hasProperty("name", is("Peter")),
hasProperty("date", is(parse("1980-01-01")))
),
allOf(
hasProperty("age", is("081")),
hasProperty("name", is("John")),
hasProperty("date", is(parse("1980-01-22")))
)
));
}
}
And let's review in details:
containsExactly
contains method is an alternative for it. Whereas hasItem is more like assertj.contains.
tuple
May be replaced by combination of allOf and hasProperty. In my opinion it looks ugly and I would think about just using new Person("a","b","c"). Unless you have some extra fields that you do not want to verify.
parse
Here I've just used same method for both of them. If you will take a more precise look on it, you will notice that this method has nothing to do with matchers. It is just parses string to date using new SimpleDateFormat("yyyy-MM-dd"). If you don't want to use assertj's you could easily extract it to some util class.
I use Jersey and I have the following Rest function which returns a JSON string when my server is deployed:
#GET
#Path("getallemployees")
#Produces("application/json")
public Response getAllEmployees() {
//building the entity object which is List<Employee>
return Response.ok(entity).build();
}
I need to develop some unit tests (not integration testing) and I want to somehow mock the HTTPRequest that invokes this method and then get the json String. The best option would be to use mockito for this.
Is there any suggestion on how to do it ?
Thanks !!
The problem is that the method returns a Response object to the caller which is deep within the framework code. It doesn't return JSON strings.
You can use Mockito, if you need to mock something inside the method itself. That should work.
But you may need to take the value returned by the method and convert it to JSON like this if you are using Jackson with Jersey.
Response response = getAllEmployees();
Object retval = response.getEntity();
try {
ObjectMapper mapper = new ObjectMapper();
// I like this formatting. You can change it.
mapper.configure(Feature.INDENT_OUTPUT, true);
mapper.configure(Feature.WRITE_ENUMS_USING_TO_STRING, true);
mapper.configure(Feature.USE_ANNOTATIONS, false);
mapper.configure(Feature.FAIL_ON_EMPTY_BEANS, false);
mapper.setSerializationInclusion(Inclusion.NON_NULL);
mapper.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
mapper.getSerializationConfig().withSerializationInclusion(JsonSerialize.Inclusion.NON_NULL);
String json = mapper.writeValueAsString(retval);
... assert something about the string
} catch (JsonProcessingException e) {
// do something
} catch (IOException e) {
// do something
}
Some of this is guess work and speculation on my part but it may help. You could try using the Jersey Test Framework with the InMemoryTestContainerFactory:
It starts Jersey application and directly calls internal APIs to handle request created by client provided by test framework. There is no network communication involved. This containers does not support servlet and other container dependent features, but it is a perfect choice for simple unit tests.
It looks like to use it, all you need to do is extend JerseyTest and then override getTestContainerFactory() and follow the rest of the instructions, e.g.:
public class EmployeeResourceTest extends JerseyTest {
#Override
protected Application configure() {
// set up employee resource with mock dependencies etc...
return new ResourceConfig().registerInstances(employeeResource);
}
#Test
public void getAllEmployees() {
final String response = target("getallemployees").request().get(String.class);
// assert etc...
}
}
I used registerInstances instead of registerClasses in configure() as it looks like you can present a ready made Resource but set up with any mock dependencies you may want - although I haven't tried this myself.
The test class is a bit inflexible as you can only do one-time set up of dependencies in the configure() method, so it might be worth investigating using the MockitoJUnitRunner - although I'm not sure if it will work with the JerseyTest inheritance. It could allow you to do add behaviour to mocks in each #Test method, e.g.:
#Mock
private EmployeeResourceDependency dependency;
#InjectMocks
private EmployeeResource employeeResource;
// configure() as above but without mock setup up etc...
#Test
public void getAllEmployees() {
given(dependency.getEmployees()).willReturn(...);
// etc...
But like I said it might not be possible to mix them at all.
I want to load an objet and forget that it comes from hibernate! That's it, I just do something as:
MyClass myObject = MyClassDAO.getUnproxiedObject(objectID);
and than I have a real instance of myObj (and not from a Hibernate proxy) with all attributes set with the values from the database, so that I can't distinguish it from a manually created object.
In this thread a method is present to create an unproxied object, but it does not treats the issue of eager loding the objects, what I suppose is necessary for achieving my ultimate goals.
For those who are wondering why would I want such objects, I need to serialize then to Json with Gson, but I think it would have many other uses for many people.
Use FetchType.EAGER to eagerly load all the relations. Specifically for JSON serialization, if you are building a web application consider using an OpenSessionInView interceptor for your HTTP requests.
after testing I found out that the method given in the citted post did exactly what I was looking for.
The reason hibernate doesn't de-proxy while rendering with GSON is that GSON uses reflection to serialize the fields rather than using the getters of the Hibernate object. To workaround, you need to register a new TypeHierarchyAdapter that will de-proxy the object as GSON is serializing.
Here's my approach:
GsonBuilder builder = new GsonBuilder();
builder.registerTypeHierarchyAdapter(HibernateProxy.class, new HibernateProxySerializer());
String jsonLove = gson.toJson(objToSerialize);
Here's the HibernateProxySerializer:
public class HibernateProxySerializer implements JsonSerializer<HibernateProxy> {
#Override
public JsonElement serialize(HibernateProxy proxyObj, Type arg1, JsonSerializationContext arg2) {
try {
GsonBuilder gsonBuilder = new GsonBuilder();
//below ensures deep deproxied serialization
gsonBuilder.registerTypeHierarchyAdapter(HibernateProxy.class, new HibernateProxySerializer());
Object deProxied = proxyObj.getHibernateLazyInitializer().getImplementation();
return gsonBuilder.create().toJsonTree(deProxied);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}