Creating an Abstract Interface around DB Connection - java

I was reading this article on Unit Testing. It seems pretty straightforward, but there was a section that interested me and I wanted to see if someone could please provide an explanation or example of what this means. I think I understand it but maybe not well enough.
Write test cases that are independent of each other. For example, if a class depends on a database, do not write a case that interacts with the database to test the class. Instead, create an abstract interface around that database connection and implement that interface with a mock object.
What does it mean to:
create an abstract interface around the db connection?
then implement it with a mock object?
I am more questioning the first part (1) but if someone can explain both parts that would be helpful. Thanks.

ONE: The "abstract data interface" simply means that you provide an interface with methods for storing and finding data in a business oriented way, rather than use the database connection directly. You can then implement this interface to store data in different ways: an sql database, a file based approach, etc. Such a class in some patterns is also referred to as "data access object" (DAO).
public interface PersonDao {
void store(Person personToStore);
Person findById(String id);
}
public class SqlPersonDao implements PersonDao {
#Override
void store(Person personToStore) {
// use database connection here ...
}
}
Basically in a unit test you always want to mock anything that is not your system under test and has a complex behaviour you cannot control. That is especially true for things like system time, for example if a class uses system time, for tests you want a way to inject a predefined time overriding the system clock.
TWO:
In unit tests you don't want to be affected by bugs in any dependency. For a unit using the PersonDao, the PersonDaowould be such a dependency. Rather than relying on the real implementation's behaviour, you want to exactly define the results you expect (using the notation of the Mockito mocking framework and the AssertJ validation framework here):
class MyUnitTest {
// system under test
MyUnit sut;
#Mock
PersonDao personDaoMock;
#BeforeEach
public setup() {
initMocks(this);
sut = new MyUnit("some", "parameters");
}
#Test
void myTest() {
// setup test environment using a mock
var somePerson = new Person("101", "John", "Doe");
doReturn(somePerson).when(personDaoMock.findById("101"));
// run test
var actualValue = sut.doSomething();
// check results
assertThat(actualValue).isNotNull();
}
}

Related

What is the point in unit testing mock returned data?

Consider the scenario where I am mocking certain service and its method.
Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");
//assert
assertEquals("Jim", emp.getName(1));
assertEquals("Mark", emp.getName(2));
In the above code when emp.getName(1) is called then mock will return Jim and when emp.getName(2) is called mock will return Mark. My Question is I am declaring the behavior of Mock and checking it assertEquals what is the point in having above(or same kind of) assert statements? These are obviously going to pass. it is simply like checking 3==(1+2) what is the point? When will these tests fail (apart from changing the return type and param type)?
As you noted, these kind of tests are pointless (unless you're writing a unit test for Mockito itself, of course :-)).
The point of mocking is to eliminate external dependencies so you can unit-test your code without depending on other classes' code. For example, let's assume you have a class that uses the Employee class you described:
public class EmployeeExaminer {
public boolean isJim(Employee e, int i) {
return "Jim".equals(e.getName(i));
}
}
And you'd like to write a unit test for it. Of course, you could use the actual Employee class, but then your test won't be a unit-test any more - it would depend on Employee's implementation. Here's where mocking comes in handy - it allows you to replace Employee with a predictable behavior so you could write a stable unit test:
// The object under test
EmployeeExaminer ee = new EmployeeExaminer();
// A mock Employee used for tests:
Employee emp = mock(Employee.class);
when(emp.getName(1)).thenReturn("Jim");
when(emp.getName(2)).thenReturn("Mark");
// Assert EmployeeExaminer's behavior:
assertTrue(ee.isJim(emp, 1));
assertFalse(ee.isJim(emp, 2));
In your case you are testing a getter, I don't know why you are testing it and no clue why would you need to mock it. From the code you are providing this is useless.
There is many scenarios where mocking make sense when you write unit-test you have to be pragmatic, you should test behaviors and mock dependencies.
Here you aren't testing behavior and you are mocking the class under test.
There is no point in that test.
Mocks are only useful for injecting dependencies into classes and testing that a particular behaviour interacts with that dependency correctly, or for allowing you to test some behaviour that requires an interface you don't care about in the test you are writing.
Mocking the class under test means you aren't even really testing that class.
If the emp variable was being injected into another class and then that class was being tested, then I could see some kind of point to it.
Above testcase is trying to test a POJO.
Actually, You can ignore to test POJO's, or in other words, they are automatically tested when testing other basic functionalities. (there are also utilities as mean-beans to test POJO's)
Goal of unit-testing is to test the functionality without connecting to any external systems. If you are connecting to any external system, that is considered integration testing.
Mocking an object helps in creating mock objects that cannot be created during unit-testing, and testing behavior/logic based on what the mocked object (or real object when connecting to external system) data is returned.
Mocks are structures that simulate behaviour of external dependencies that you don't/can't have or which can't operate properly in the context of your test, because they depend on other external systems themselves (e.g. a connection to a server). Therefore a test like you've described is indeed not very helpful, because you basically try to verify the simulated behaviour of your mocks and nothing else.
A better example would be a class EmployeeValidator that depends on another system EmployeeService, which sends a request to an external server. The server might not be available in the current context of your test, so you need to mock the service that makes the request and simulate the behaviour of that.
class EmployeeValidator {
private final EmployeeService service;
public EmployeeValidator(EmployeeService service) {
this.service = service;
}
public List<Employee> employeesWithMaxSalary(int maxSalary) {
List<Employee> allEmployees = service.getAll(); // Possible call to external system via HTTP or so.
List<Employee> filtered = new LinkedList<>();
for(Employee e : allEmployees) {
if(e.getSalary() <= maxSalary) {
filtered.add(e);
}
}
return filtered;
}
}
Then you can write a test which mocks the EmployeeService and simulates the call to the external system. Afterwards, you can verify that everything went as planned.
#Test
public void shouldContainAllEmployeesWithSalaryFiveThousand() {
// Given - Define behaviour
EmployeeService mockService = mock(EmployeeService.class);
when(mockService.getAll()).thenReturn(createEmployeeList());
// When - Operate the system under test
// Inject the mock
EmployeeValidator ev = new EmployeeValidator(mockService);
// System calls EmployeeService#getAll() internally but this is mocked away here
List<Employee> filtered = ev.employeesWithMaxSalary(5000);
// Then - Check correct results
assertThat(filtered.size(), is(3)); // There are only 3 employees with Salary <= 5000
verify(mockService, times(1)).getAll(); // The service method was called exactly one time.
}
private List<Employee> createEmployeeList() {
// Create some dummy Employees
}

Best approach for unit testing with data

I have a lot of DAO classes I need to test on a Spring project.
I am already using DBUnit to mock my database, however I use the #Before annotation to create objects and compare them after tests on create/update/delete operations.
#DatabaseSetup(value = { "/db_data/dao/common.xml", "/db_data/dao/myDAOCommonTest.xml" })
#DbUnitConfiguration(dataSetLoader = ReplacementDataSetLoader.class)
public class MyDAOImplTest extends AbstractDaoTU {
#Autowired
private MyDAO myDAO;
private Set<ClassNeeded> objectsNeeded = new HashSet<>();
private ClassOne classOne;
private ClassTwo classTwo;
private ClassThree classThree;
#Override
public void setUp() throws Exception {
super.setUp();
this.objectsNeeded.add(somethingComingFromTheMotherClass);
this.classOne = new ClassOne();
this.classOne.setIdClassOne(1L)
this.classOne.setObjectsNeeded(this.objectsNeeded);
// ... Many other sets
this.classTwo = new ClassTwo();
this.classTwo.setIdClassTwo(1L);
this.classTwo.setClassOne(this.classOne);
// ... Many other sets
// ... Other sets follow for a lot of other objects
}
#Test
public void testOne {
// ...
}
// ... Other tests follow
}
I am using an ORM (Hibernate in this case), and most objects are inter-dependent. My dao functions mostly need complete objects to be called, so I must create the objects before testing.
My questions are the following :
Is there a better approach to unit test DAOs ?
What tools do you know to make this easier/faster to write ? (I am using maven for packaging)
Thanks for your help !
DB Unit complicates the maintenance of the tests as it increases the number of places that need updates when something changes. Additionally it separates the data preparation from the tests too much so it's hard to find which of the data relates to which tests.
Ideally each test prepares data for itself. This removes global state and keeps related things together.
To prepare the data just create entities and save them in the very same test. You can use randomization and transaction rollbacks to isolate the tests. Here is an example from one of my projects:
#Test public void returnsExperimentAsItWasSaved() {
Experiment original = Experiment.random();
experimentRepository.save(original);
flushToDbAndClearCache();
Experiment fromDb = experimentRepository.findOne(original.getExperimentId());
assertReflectionEquals(original, fromDb);
}
Note, that the very same DAO class is used to prepare the data.
The best way is to develop your tests as you would develop your code: refactor to minimize duplication, extract reusable services, etc.
So, you'll probably create some TestCaseFactory that chains up a whole set of objects and saves them using your actual DAO's. Then, you can call them from an #Before as you did. If you need a lot of different sets of objects, you can create different methods or a parameter object etc.
And do a cleanup of all test data in an #After.

How to mock java methods of superclass using powermock or any mock tool?

Super class
public class BasicDao {
public Object createQuery() {
return new Object();
}
}
Implementation
public class MyDAO implements BasicDao {
public Object getMyData() {
Object obj = createQuery();
// more code...
return ...;
}
}
I need to test getMyData() method and I want to mock/suppress createQuery() method cos it will fail on test env.
Thanks!
Don't do tests this way. This is called partial mocking and this is wrong, it means that the code that have been written is not using good Object Oriented design. One should favor Composition OVER Inheritance.
Nevertheless DAO are object that represents the boundary of your system, i.e.
one side is Object Oriented
one side is Relational
In this case you should write integration tests,
insert data in a DB, actual instance or in-memory instance (h2, hsqldb, ...)
prepare your data, there's plenty possibilities here (DbUnit, DbSetup, ...)
configure and run your DAO tests on this database
It may require more setup and more time to run but it is better in the long run.
more robust mapping testing
easier to change the technical implementation, without changing tests
run against a database, you can detect configuration issues/challenges sooner, and make sure they don't break 3 years later
Also answer of #user3386493 is technically correct but I'd suggest to use this kind of stubbing with spies (otherwise actual method code is executed) :
MyDAO daoSpy = Mockito.spy(new MyDAO());
doReturn(new Object()).when(daoSpy).createQuery();
You can do that by using Mockito.
#Test
public void testGetMyData() {
MyDAO dao = new MyDAO();
MyDAO daoSpy = Mockito.spy(dao);
Mockito.when(daoSpy.createQuery()).thenReturn(new Object());
}

Test Method Called Without Having Argument In Test Class

I have a class which takes a message with payload String.
The payload is then split and used to create an Entity which is passed to DAOInterface to persist.
How can you test the call daoInterface.insert(entity) has been made?
To Mock the DAOInterface and then verify the call to DAO requires the entity in the test class i.e.
verify(daoInterface).insert(entity);
Is this bad design i.e. creating the entity at this stage? Should the Sting[] split be passed to the DAOImplementaion and initialized there. Example problem,
public class ServiceClass {
#AutoWire
private DAOInterface daoInterface;
public void serviceMessage(Message<String> message) {
MessageHeaders mh = new MessageHeaders(message.getHeaders());
String[] split = ((String) mh.get("payload")).split("_");
code omitted
...
String type = mh.get("WhatType");
Entity entity = new Entity(split[0], split[1], split[2]);
if (type.equals("one"))
{
daoInterface.insert(entity); //How to test?
}
else
{
if (type.equals("two"))
{
doaInterface.modify(entity); //How to test?
}
}
}
}
You can verify with Mockito Matchers.
If you only care that the method is called with some Entity, you can verify that with
verify(daoInterface).insert(any(Entity.class));
If you care about which Entity, and the Entity class has an equals method, you can make an entity that should be equal to the one created and verify with
verify(daoInterface).insert(eq(expectedEntity);
If it's more complex than either of these cases, you can also write your own argument matchers.
The easiest thing you can do is injecting another collaborator to the service which will transform payload to Entity. This way you can keep control on object creation (Inversion of Control). Something like the example below injected to the ServiceClass should do the job:
interface PayloadTransformer {
public Entity transform(String payload);
}
This way your code will be easy to test and you split responsibilities which is usually a good thing. Have a look on Single Responsibility principle
Pushing transformation logic down to dao is almost never a good idea.
BTW. you can write else if without additional brackets and indentations. It's more readable like:
if (a) {
// do something
} else if (b) {
// do something
} else {
// do something
}
The last advice ServiceClass is really poor name for class. The word class is redundant here. Just name it Service, EntityService, MessageService or something which fits your case well.
I wouldn't name field with suffix *Interface as well. Underneath is some implementation injected, I assume. Better name it entityDao or just dao. It's up to you though :)
If you use a test framework like PowerMock, you can invoke private constructors and private methods in your test. This makes it easy to inject mock objects like a mock DAOInterface so you can retrieve it later and test it's been called.
For example, in PowerMock, to call a private constructor:
public class ServiceClass{
#Autowire
private final DAOInterface dao;
public ServiceClass() {
}
private ServiceClass(DAOInterface dao) {
this.dao = dao;
}
}
You simply do:
PrivateConstructorInstantiationDemo instance = WhiteBox.invokeConstructor(
PrivateConstructorInstantiationDemo.class,
new MockDAOInterface() );
So if you're using a dependency inject framework like above, this dovetails nicely. You don't normally have the dependency injection working during test, since it usually requires booting a large chunk of code with a lot of configuration.
By adding a single private constructor, you avoid breaking encapsulation, but you can still inject your mock object into the code during test with a test framework like PowerMock. This is considered best practice.
You could break encapsulation and add publicly accessible methods or ctors to the SeviceClass, but if you don't need them for your design it's not good practice to add them only for test. That's why people put such effort into bypassing encapsulation in frameworks like Mockito and PowerMock. It's not just a dodge around private code, it's because you want to keep the encapsulation while still being able to test.
EDIT:
If you're not familiar with making mock objects, you should do some Google searches on the subject. It's very common and a good skill to have. With the above code, you could make your own mock object. But making mocks is so common that most test frameworks will do this for you.
For example, in PowerMock, I just looked at their page on making mocks here. You can make a mock like this
DAOInteface myMock = createMock(DAOInterface.class);
You can then ask the mock to verify that methods are called:
expect(myMock.someMethod());
Now the mock 'expects' that method to be called, and if it isn't, it'll generate an error for your test. Pretty sweet actually.
You can also return values from a call:
expect(myMock.insert()).andReturn("Test succeeded");
so your code would then see the value "Test succeeded" when it called that method. I don't see that 'insert' does return a value, that's just an example.

Can we mock a method in service while testing the service itself?

I am working on a project where I am using MyBatis annotations as persistence framework. Therefore, I have to create an interface for the 'mapper' and compose the mapper in the service like :
class XYZServiceImpl{
public XYZMapper getXYZMapper(){
return SessionUtil.getSqlSession().getMapper(XYZMapper.class)
}
}
Now while unit testing the service with Mockito, I am trying to inject a mock for the mapper. But since I am injecting mock in an instance of XYZService, how can mock a method of the service itself, in this case getXYZMapper() is what I am trying to stub. Although I have got a solution of creating the instance XYZMapper in the service and not call on demand like the above code does something like :
Class XYZServiceImpl{
XYZMapper mapper;
public void useXYZMapper(){
mapper = SessionUtil.getSqlSession().getMapper(XYZMapper.class);
}
}
But that would bring a lot of code changes (ofcourse I can refactor) but is there a way to achieve without having to make code changes?
Also what would be a 'purist' way to have a mapper instance in the class is it the method 1 that is better than method 2 in terms of performance?
EDIT : Here XYZMapper is an interface. Something like :
public interface XYZMapper{
#Select("SELECT * FROM someclass WHERE id = #{id}")
public SomeClass getSomeClass(int id);
}
EDIT : I am facing a similar situation but with a variance that I have a service that I do want to test like XYZServiceImpl. Now it has a method getXYZDetails() which has a lot of business logic handled within the service. Now if getXYZDetails looks like the following :
public XYZDetails getXYZDetails(int id){
XYZDetails details = new XYZDetails();
details.set1Details(fetchSet1Details(id));
//Perform some business logic
details.set2Details(fetchSet2Details(id));
if(details.set2Details() != null){
for(int i = 0; i < details.set2Details().size(); i++){
flushTheseDetails(i);
}
}
.
.
}
Kindly notice that fetchSet1Details(), fetchSet2Details(), flushTheseDetails are public service, public and private service respectively.
I want to know of a method that can mock/stub these methods while testing getXYZDetails() thus enabling me to
There are several options you can use.
Inject dependency
This works only for simple methods like getXYZMapper when method only returns external dependency of you object. This may require to create new XYZServiceImpl instances if for example mapper is bound to connection which is opened per request.
Encapsulate method behavior in object
Another way to achieve similar result is to use a factory or service locator
like this:
public class XYZServiceImpl {
public XYZServiceImpl(XYZMapperFactory mapperFactory) {
this.mapperFactory = mapperFactory;
}
public XYZMapper getXYZMapper() {
return mapperFactory.getMapper();
}
}
This will allow you easily substitute factory in test with implementation which returns mock mapper.
The similar approach can be used for other methods fetchSet1Details, fetchSet2Details, flushTheseDetails that is moving them to other class or classes. If the method contains complex (and may be loosely related) logic it is a good candidate to be moved in separate class. Think about what these methods do. Usually you can move some essential and unrelated part of them to other class or classes and this makes mocking them much easier.
Subclass
This is not recommended but in legacy code sometimes is very helpful as a temporary solution.
In your test subclass you class under test and override methods you need:
#Test
public void someTest() {
XYZServiceImpl sut = new XYZServiceImpl() {
public XYZMapper getXYZMapper() {
return mapperMock;
}
public Whatever fetchSet1Details() {
return whateverYouNeedInTest;
}
}
sut.invokeMethodUnderTest();
}
The only thing you may need to do is to change access modifier of private method to package-private or protected so you can override them.
Spying
This method in also discouraged but you can use mockito spies:
XYZServiceImpl realService = new XYZServiceImpl();
XYZServiceImpl spy = Mockito.spy(realService);
when(spy.fetchSet1Details()).thenReturn(whaeveryouneed);
when(spy.getXYZMapper()).thenReturn(mockMapper);
spy.methodUnderTest();
I would suggest the "purist" way of doing this is to accept an XYZMapper instance in your constructor and store it in a local field.
In production use, you can pass an e.g. SQLXYZMapper, which will interact with your database. In test use, you can pass in a mocked object that you can verify interactions with.

Categories