In my company we are starting with unit testing and for what I understand unit test should not use a connection with a real database. My question is, how should I test the persistance layer? like for instance, if a query returns the expected results.
I've read that you can use Mockito to mock the database results, but It doesn't make sense to me in this case.
#Test
public void happyPathScenario(){
Customer sampleCustomer = new Customer();
sampleCustomer.setFirstName("Susan");
sampleCustomer.setLastName("Ivanova");
EntityManager entityManager = mock(EntityManager.class);
when(entityManager.find(Customer.class,1L)).thenReturn(sampleCustomer);
CustomerReader customerReader = new CustomerReader();
customerReader.setEntityManager(entityManager);
String fullName = customerReader.findFullName(1L);
assertEquals("Susan Ivanova",fullName);
}
It would be impossible for this test to fail. So, how can I apply this to a real world case? I have a function that queries actual customers and shows them to the user on a table, this happens on a JSF Bean (which is the responsible for the presentation layer). If a use mockito to mock the results of the query, theres nothing left to test (maybe the table render or some other thing?).
For the persistance layer, should I apply integration test or is there a "correct" way to use unit test?
Related
I got off from writing basic unit tests using JUnit for simple methods that adds two numbers. I can verify the result by using the assert* family of function calls. Now I want to unit test a Spring Boot controller.
Here is the example of the unit test class -
public class MyJunitTest {
private MockMvc mockMvc;
#Mock
private MyService service;
#InjectMocks
private MyController controller;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
}
#Test
public void unitTestGetAssessmentDetails() {
when(service.getTest(Someobject.class)).thenReturn(customObjectWithValues);
Results results = controller.getCall(someRequestObject);
assertEquals(results, someOtherObjectPrefilledWithValues);
}
}
My question is, if I know the values set in customObjectWithValues, then someOtherObjectPrefilledWithValues is also set by me, then assertEquals will always give a pass to the test, right? It's essentially testing if 1==1 kind of test. So what is the point of doing these unit tests? I know that the service object should not connect to the actual DB, and hence we are mocking it. So what is the point of doing these tests? Am I missing the bigger picture here as to how to view unit tests?
P.S. - Please feel free to remove this question if it violates the rules of this forum.
Your test verifies that getCall returns the expected results;
this is a black box test.
Since you are writing a unit test,
this is only sufficient to "pretend" to perform a unit test.
This technique is common in firms that conflate code quality with
unit test code coverage.
A better technique is to identify the steps that will be taken by the controller class and to verify that each was executed (perhaps in the correct order, as well).
I will assume that MyController.getCall looks something like this:
#Autowired
private MyService myService;
public BlammyReturnValueType getCall(final BlammyRequestType request)
{
final BlammyReturnValueType returnValue;
returnValue = myService.someServiceMethod(request);
return returnValue;
}
In this case,
I would add the following to the unitTestGetAssessmentDetails test method:
... The current stuff including the assert.
Mockito.verify(service, times(1)).someServiceMethod(customObjectWithValues);
This will confirm that the service method was called exactly one time,
which is correct in this example.
Ok so, unit testing is more about testing the logic written in your function/controller/service. Now, your function might be very simple or it might be very complex. For ex, your function might be taking and UserId in request, connect to database, gets the data and return it and since you are mocking the database connection, you might feel like if you are passing the mocked object as database response, you will obviously get the same response, so what's the point of testing. It might seem correct to not test at all in this case. But let me give you another example, say you have a very complex function, which takes some UserId, gets the whole year data of users banking history, cumulates it and calculates the amount user earned for this year. Now, think how complex this function is. Now since you have mocked the DB connection you will pass in some data, a lot of computation goes on inside and gives the user an amount earned as Interest on saving. Now, for a given mocked data, you know the answer should come as some X amount. Now, over the time, someone made a mistake (maybe subtracted something which was needed to be added). Now, when you run the test. This test will fail and you know something is wrong with logic. Not here you are not directly expecting the output to be equal to your mocked data, some computation has been done over the data, so to verify after each change that function logic is correct, you need to write a unit test to verify it. Now if you see here, your are not testing 1==1 but something different. This is why people write unit tests, to check their logic inside a unit of code.
Hope this helps.
Usually we have 3 layers which are Controller, Service, Repository (DAO if you prefer). I usually do not test controllers because I do not put any logic in them, I just define the endpoint and call the service. The service is what I heavily unit test so you would inject the mocks into your service. Then you would mock your Repository so it wouldn't try to connect to a database.
#InjectMocks
private MyService service;
#Mock
private MyRepository myrepo
#Test
public void unitTestGetAssessmentDetails() {
when(myrepo.find(someInt)).thenReturn(customObjectWithValues);
Results results = service.serviceMethod(someRequestObject);
assertEquals(results, someOtherObjectPrefilledWithValues);
}
Since controllers are supposed to have no logic they shouldn't need unit test because as you correctly say it's a 1==1 test. But they would be tested by integration tests
As a person has no experience before in unit testing and mocking, I followed beginner tutorials about JUnit with Mockito and I do some practice.
Now, I need to unit test some class methods which do basic database operations on a MySQL database. I don't want to make real changes on the database.
In my code:
#InjectMocks private DBConnection dbConnection;
#Mock private DBConnection mockDBConnection;
#Test
public void testDropTable() {
Mockito.when(mockDBConnection.dropTable()).thenReturn(0);
// dropTable() returns 0 if table dropped
int result = dbConnection.dropTable();
Assert.assertEquals(result, 0);
}
To verify(with assertEquals() ) result of the test, I am calling real dropTable() method, and it really drops table( Actually it is obvious, because I'm calling on real DBConnection instance)
Is there anyway to verify the methods like that, without accessing the real database? Or did I misunderstand the concept of Unit Testing and Mocking?
Imagine the following... You have two cars, one is a real car, another is a fake (mock) car. Now you get into the real car and drive off. Why do you expect not to move? You didn't do anything with the fake car, so even if you told it "Do not move if I start driving", this doesn't change the fact that the real car WILL move when you drive off.
Same thing here, you created a fake DBConnection and a real one. The real one will do whatever the real one does. The fake one can be configured to do different stuff, like you did with Mockito.when(...). But that doesn't change the behavior of the real one.
Your test is effectively meaningless, because your only choice here is to get rid of the mock, because it doesn't serve any meaningful purpose. You do not test a mock. What for? That's like creating a fake car and testing that - it doesn't tell you anything about the real car. You do not need to test the fake car to find out that it will do X if you told it to do X in that test.
There are two ways you can test your DBConnection class:
a) You can connect it to a database and check that it does what it should. This would, of course, be an integration test and not a unit test anymore. In some cases you can use a in-memory database like HSQLDB to speed up this test. But at least in the end you can be reasonably sure that your code does what it is supposed to be doing.
b) IF and only IF DBConnection has some objects internally that do the actual talking to the database, you can, perhaps, mock those and then test DBConnection. Of course, this only moves your problem to another layer, because then you aren't sure that those objects work - you will only know that DBConnection works IF those objects work. While this is good to know, it does not answer the question if your db code will work in the end.
In the end, you can only test db connections completely by connecting to a db. Everything else is not a complete test.
Why not consider using an in-memory database for your unit tests. Maybe using a DAO pattern to easily switch between real and in-memory.
Keep the actual database interaction layer thin as possible to ensure you abstract your logic away in separate classes, this makes testing much easier, as in this case you can mock the DB object and focus on testing your logic.
Also decide what you are testing, most likely you want to test your logic, not the logic of the 3rd party database connector, so focus your tests on that.
Consider a suite of Integration or System tests to test the applications features against a real database, should you require this level of testing, but for unit tests, in-memory should be fine.
The overall confidence of your app can be achieved using be a combination of unit and integration tests.
For the #Florian Schaetz's comment, do I need to do something like that:
AuthenticatorApplicationInterface.java
public interface AuthenticatorInterface {
public boolean authenticateUser(String username, String password) throws EmptyCredentialsException;
}
AuthenticatorApplication.java
public class AuthenticatorApplication {
private AuthenticatorInterface authenticator;
public AuthenticatorApplication(AuthenticatorInterface authenticator) {
this.authenticator = authenticator;
}
public boolean authenticate(String username, String password) throws NotAuthenticatedException {
boolean authenticated;
authenticated = this.authenticator.authenticateUser(username, password);
return authenticated;
}
}
AuthenticatorApplicationTest.java
public class AuthenticatorApplicationTest {
#Test
public void testAuthenticate() throws EmptyCredentialsException {
AuthenticatorInterface authenticatorMock;
AuthenticatorApplication authenticator;
String username = "username";
String password = "noncorrectpassword";
authenticatorMock = Mockito.mock(AuthenticatorInterface.class);
authenticator = new AuthenticatorApplication(authenticatorMock);
when(authenticatorMock.authenticateUser(username, password)).thenReturn(false);
boolean actual = authenticator.authenticate(username, password);
assertFalse(actual);
}
}
I know this is a basic question but due to lack of my knowledge I couldn't start writing test for my application. So here I am trying to learn and understand what to test and how to test based on my application scenario.
Class MyController {
MyService service = new MyService();
List<String> myList = service.generateSomeList(keyVal);
model.add("myList", myList);
}
Class MyService {
ThirdPatryService extService = new ThirdPatryService ();
MyDao dao = new MyDao();
public List<String> generateSomeList(Long key) {
List<String> resultList = dao.fetchMyList(key);
extService.processData(resultList); //using 3rd party service to process result. It doesn't return anything.
return formattedList(resultList);
}
private List<String> formattedList(List<String> listToProcess) {
//do some formatting
}
}
Class MyDao {
List<String> fetchMyList(key) {
//Use DB connection to run sql and return result
}
}
I want to do both unit testing and integration testing. So some of my questions are:
Do I have to do unit testing for MyDao? I don't think so since I can test query result by testing service level.
What can be the possible test cases for service level? I can think of test result from db and test formatting function. Any other test that I missed?
While testing generateSomeList() method is that OK to create dummy String list and test it against result? Like code below Am I creating list myself and testing myself. IS this proper/correct way to write test?
#Test
public void generateSomeListTest() {
//Step 1: Create dummy string list e.g. dummyList =["test1", "test2", "test3"]
//Step 2: when(mydao.fetchMyList(anyLong()).thenReturn(dummyList);
//Step 4: result=service.generateSomelist(123L);
//Step 5: assertEquals(result[i], dummyList[i]);
}
I don't think I have to test third party service but I think I have to make sure it is being called. Is this correct? If yes how can I do that with Mockito?
How to make sure thirdparty service has really done the processing of my data. Since its return type is void how can I do test it really done its job e.g like send email
Do I have to write test for controller or I can just write integration test.
I really appreciate if you could answer these question to understand the testing part for the application.
Thanks.
They're not really unit tests, but yes, you should test your DAOs. One of the main points in using DAOs is precisely that they're relatively easy to test (you store some test data in the database, then call a DAO method which executes a query, and check that the method returns what it should return), and that they make the service layer easy to test by mocking the DAOs. You should definitely not use the real DAOs when testing the services. Ue mock DAOs. That willmake the service tests much simpler, and much much faster.
Testing the results from DB is the job of the DAO test. The service test should use a mock DAO that returns hard-coded results, and checks that the service foes what it should do with these hard-coded results (formatting, in this case)
Yes, it's fine.
Usually, it's sufficient to stub the dependencies. Verifying that they have been called is often redundant. In that case, it could be a good idea since the third party service doesn't return anything. But that's a code smell. Why doesn't it return something? See the method verify() in Mockito. It's the very first point in the Mockito documentation: http://docs.mockito.googlecode.com/hg/latest/org/mockito/Mockito.html#1
The third party service is supposed to have been tested separately and thus be reliable. So you're supposed to assume that it does what its documentation says it does. The test for A which uses B is not supposed to test B. Only A. The test of B tests B.
A unit test is usually simpler to write and faster to execute. It's also easier to test corner cases with unit tests. Integration tests should be more coarse-grained.
Just a note: what your code severely lacks as is is dependency injection. That's what will make your code testable. It's very hard to test as is because the controller creates its service, which creates its DAO. Instead, the controller should be injected with the service, and the service should be injected with the DAO. That's what allows injecting a mock DAO in the service to test the service in isolation, and to inject a mock service into the controller to test the controller in isolation.
Imagine unit testing the following sample scenario. Let's say I've mocked out the CustomerDAO in order to return a valid customer and customer orders. Testing this scenario is fairly easy. Except when I get to testing the boolean for whether or not a customer has orders. In some real world scenarios they will not have orders. So do I need to add some condition in my mock DAO that will return a customer with no orders, and then test that as well? Now imagine it is much more complicated and there are several pieces of the DTO that could contain various bits of information depending on the real results coming back from the database. Do I need to test all of those various conditions?
public class Manager {
public CustomerDTO getCustomerInformation() {
CustomerDAO customerDAO = new CustomerDAO();
CustomerDTO customerDTO = new CustomerDTO();
customerDTO.setCustomer(customerDAO.getCustomer(1));
customerDTO.setCustomerOrders(customerDAO.getCustomerOrders(1));
if (!customerDTO.getCustomerOrders.isEmpty()) {
customerDTO.setHasCustomerOrders(true);
}
return customerDTO;
}
}
In short, I think yes you should test that when the DAO returns various things that the expected state exists on the DTO. Otherwise how can you have an confidence that the DTO will be an accurate representation of the data that was in the datastore?
You should create either a mock DAO per test with the required data for the test, or a mock DAO for each state that needs to be tested.
I'd probably have tests like:
CustomerHasOrders_WhenDaoReturnsNoOrders_ReturnsFalse
CustomerHasOrders_WhenDaoReturnsOrders_ReturnsTrue
GetCustomer_WhenDaoReturnsCustomer_CustomerIsSame
GetCustomerOrders_WhenDaoReturnsOrders_OrdersAreTheSame
GetCustomerOrders_WhenDaoReturnsNoOrders_OrdersAreEmpty
and then tests for what happens if any of the calls to the Dao fail...
In this example it seems that the flag is redundant in the DTO, as it is just different representations of other data. You could implement that as an extension method on CustomerDTO, or some logic in the setCustomerOrders. If the DTO is to be sent over the wire and the functionality won't neccessarily be there then you could exclude the property and the client could just do the check to see if there are any orders in the same way you are customerDTO.getCustomerOrders.isEmpty()
You want to test if Manager is converting Customer and it's related data to CustomerDTO. So yes you have to test all those different scenarios. But don't do it all in one test. Each test should reach it's end either finishing with success or failure. What I mean:
// Don't do this
[Test]
public void Manager_Converts_Customer_to_CustomerDTO()
{
// mock setup
var dto = Manager.GetCustomer();
Assert.That(dto, Is.Not.Null);
Assert.That(dto.Firstname, Is.EqualTo("what has been setup in mock"));
Assert.That(dto.Orders.Count, Is.EqualTo(expected_set_in_mock));
Assert.That(dto.Orders[0].Product, Is.EqualTo(expected_set_in_mock_product));
}
Because then you have one test failing when there is one error and when there are 4 errors. You fix one bug and expect test to pass but then it fails again on next line. Put that all asserts in different tests with describing names.
I have this simple method which calls the TFS (Team foundation server) API to get WorkItemCollection object. I have just converted in to an entity class and also added it in cache. As you can see this is very simple.
How should i unit test this method. Only the important bit it does is calls TFS API. Is it worth testing such methods? If yes then how should we test it?
One way I can think is I can mock call to Query.QueryWorkItemStore(query) and return an object of type “WorkItemCollection” and see finally this method converts “WorkItemCollection” to List. And check if it was added to cache or not.
Also as I am using dependency injection pattern her so I am injecting dependency for
cache
Query
Should I only pass dependency of mocked type (Using MOQ) or I should pass proper class type.
public virtual List<Sprint> Sprint(string query)
{
List<Sprint> sprints =
Cache.Get<List<Sprint>>(query);
if (sprints == null)
{
WorkItemCollection items =
Query.QueryWorkItemStore(query);
sprints = new List<Sprint>();
foreach (WorkItem i in items)
{
Sprint sprint = new Sprint
{
ID = i.Id,
IterationPath = i.IterationPath,
AreaPath = i.AreaPath,
Title = i.Title,
State = i.State,
Goal = i.Description,
};
sprints.Add(sprint);
}
Cache.Add(sprints, query,
this.CacheExpiryInterval);
}
return sprints;
}
Should I only pass dependency of mocked type (Using MOQ) or I should pass proper class type.
In your unit tests, you should pass a mock. There are several reasons:
A mock is transparent: it allows you to check that the code under test did the right thing with the mock.
A mock gives you full control, allowing you to test scenarios that are difficult or impossible to create with the real server (e.g. throw IOException)
A mock is predictable. A real server is not - it may not even be available when you run your tests.
Things you do on a mock don't influence the outside world. You don't want to change data or crash the server by running your tests.
A test with mocks is faster. No connection to the server or real database queries have to be made.
That being said, automated integration tests which include a real server are also very useful. You just have to keep in mind that they will have lower code coverage, will be more fragile, and will be more expensive to create/run/maintain. Keep your unit tests and your integration tests separate.
edit: some collaborator objects like your Cache object may also be very unit-test friendly. If they have the same advantages as that of a mock that I list above, then you don't need to create a mock. For example, you typically don't need to mock a collection.