Mock dataManager with Mockito

Hi,
is there a way to mock dataManager with Mockito?
I want define a when(dataManager.(…)).thenReturn(…) block.
The code I want test looks like:

dataManager.load(MyClass.class).query("select .... from ...).parameter("..", param).view("myView").optional()

I tried to create:

final FluentLoader<RequestLog, UUID> fluentLoader = new FluentLoader<>(MyClass.class, dataManager);
when(dataManager.load(any(MyClass.class.getClass()))).thenReturn(fluentLoader);

But I cannot create a FluentLoader.ByQuery<> because it is only package-scoped.

I want all negative tests with JUnit and Mockito an the positive tests with integrationtests.

Is there any solution for my problem?
Thanks!

Hi,

  1. First of all, as CUBA isn’t based on Spring Boot, you will not be able to use magic Mockito annotations in tests.

  2. As DataManager itself implements some methods necessary for fluent DataManager.load() API, we should not mock the whole DataManager object. We should just mock some of its methods (loadList, load etc.).

If you are writing a unit test that tests just one class without dependencies, then you can create a child class of a DataManagerBean (or class implementing DataManager interface), and manually delegate necessary methods such as loadList, load to a mock object. Other methods such as DataManager#load() will be implicitly implemented by a class. Extended class should be created manually and injected to the class being tested.

If you need to test the whole Spring application context, but with DataManager bean mocked, you’ll need to create a second TestContainer class with modified Spring context, and use this TestContainer in tests that need DataManager mocking.

I’ve tried and succeeded in creating a sample project demonstrating how one can run test with a full Spring context but with DataManager mocked.

Take a look here: https://github.com/alexbudarov/data-manager-mock-test

1 Like

Thank you!!! Very good support!

Hi Reinhard,

an alternative approach that I used to work a lot with is to encapsulate your data fetching logic in dedicated repository beans. Just give the functionality:

dataManager.load(Customer.class).query("select e from example_Customer e where e.name = :lastName").parameter("lastName", lastName).view("myView").optional()

a dedicated place to live like CustomerRepository with a method: Optional<Customer> findCustomerByLastName(String lastName).

This way you don’t have to mock a fluent interface (like the API of DataManager) as this is normally quite problematic to do. Instead, you mock the method call to your repository, which is way easier, as it has a simpler API in terms of mocking.

It also gives you the additional benefit that you don’t mix up your business logic with database interaction logic.

I wrote an article about that topic in CBUA a while ago: Don’t squash your business logic.

For the split of integration tests and unit tests, you can still decide to do positive tests as integration tests and negative tests as unit tests. But it also adds another option:

  • write only unit tests against your business logic with the mocking of your repository
  • write only integration tests for the database interaction logic

Normally the nature of database interaction logic is to work with the DB. Mocking the DB makes little sense there. But for all the business logic, you don’t really care if it is correctly persisted - as long as you know that it gets transmitted correctly to the repository class. This is why mocking makes very much sense here.

Bye
Mario

2 Likes

Hi,
Good addition, haven’t even thought about it :frowning:

By the way, spoiler alert:
in Jmix we are going to have https://github.com/Haulmont/jmix-core/issues/122 !

1 Like

Thank you @mario! That’s exactly what I’m looking for! It was always a thorn in my side that there is no own persistence layer in CUBA. I don’t want read anything about SQL in my business logic.
Where should I create my *Repository Classes? I keep in mind that we would switch to Jmix in future.
In the sample project they created this persistence layer in global.
I think the best place for now is Business Logic > Beans. Maybe there will come an own module for persistence…
Bye Reini