The article presents a perspective and some code samples on how one could some cool stuff with Test-driven development (TDD) and Mocking. The code samples are done in Java.
Lets briefly understand what is TDD and mocking?
What is TDD?
Test-driven development, simply speaking, is a software development process in which developers write tests first and, then writing enough code to pass those tests. Once all of the tests pass, they do code refactoring to enhance code quality. Following are key advantages of adopting TDD as your development process:
- Enforces the developers to thoroughly think through various different test cases which could be used to test the functional/business requirements. It, thus, takes care of lot of bugs that could be found during QA and post-production phases which are very difficult to fix.
- Developers get to work very closely with both, business analyst and test engineers. This propagates team work.
- Code refactoring can be done in easy way.
Following diagram represents TDD process:
Following are some good pages on the web to get yourself going with TDD:
What is Mocking?
Mocking is a unit testing phenomenon which helps to test objects in isolation by replacing dependent objects with complex behavior with test objects with pre-defined/simulated behavior. These test objects are called as Mock objects.
How does TDD shine with Mocking?
In TDD, the primary objective is to pass the tests that are written first. However, in real world scenario, as one starts writing the code, one come across various cases which could be made as dependent classes. Following are different options one can do:
- Without Mocking: Write all code in the same class and pass the tests. Once the tests pass, refactor the code by extracting methods and classes. Make sure the tests pass.
- With Mocking: Instead of requiring to write all the code at once in the same class, just implement the flow by making use of dependent classes and make sure the tests pass. In doing this, just define the dependent classes, and mock them in unit tests. By doing this, one would ensure that method flow pass without having the need to write the entire code. The advantage of using mocking is the interesting behaviors that one could simulate without having need for the code. This is demonstrated later in this article with code samples. Following diagram demonstrates the fact that with mocking, one may not need to write the dependent classes and still complete the code flow while making sure all the related tests pass.
Software Requirement
We will try and see how TDD shines with mocking with this requirement. The requirement is to add a new restaurant to a restaurant database system. One should be able to add a restaurant if the mandatory data are entered.
Unit Test Written First
Looking at the requirements, one could come up with some of the following tests:
- restaurantNotCreatedDueToValidationFailure
- restaurantNotCreatedDueToPersistenceFailure
- restaurantCreated
Following is how the unit test (written first) looks like:
Unit Test: NewRestaurantTest.java
public class NewRestaurantTest {
@Before
public void setUp() throws Exception {
}
@After
public void tearDown() throws Exception {
}
@Test
public void restaurantCreated() {
}
@Test
public void restaurantNotCreatedDueToValidationFailure() {
}
@Test
public void restaurantNotCreatedDueToPersistenceFailure() {
}
}
Class Design
Looking at above tests, following different classes came into picture:
- NewRestaurant: Comprising of logic to create the restaurant
- Restaurant: Domain object representing the restaurant
- RestaurantValidation: Consisting of validation logic matching the business rules required to add a new restaurant
- RestaurantDAO: Consisting of logic to persist restaurant object into database
Java Class: NewRestaurant.java
Note the createRestaurant method in which validated and persist methods are called on classes RestaurantValidation and RestaurantDAO respectively. These methods are, however, empty methods in their respective classes. However, with these methods, the flow for creating the restaurant is complete. Look at the code below.
public Restaurant createRestaurant( Restaurant restaurant ) {
Restaurant retRest = null;
if( resVal.validated( restaurant ) ) {
if( resDAO.persist( restaurant ) ) {
retRest = new Restaurant( restaurant );
}
}
return retRest;
}
To test the above code, following code demonstrates the usage of mocking. Note how validated and persist methods on RestaurantValidation and RestaurantDAO respectively are mocked in three different tests shown below.
Unit Test: NewRestaurantTest.java
@Test
public void restaurantCreated() {
Restaurant restaurant = new Restaurant();
Mockito.when( restVal.validated(restaurant)).thenReturn( true );
Mockito.when( restDAO.persist(restaurant)).thenReturn( true );
Restaurant newRest = newRestaurant.createRestaurant(restaurant);
Mockito.verify( restVal ).validated(restaurant);
Mockito.verify( restDAO ).persist(restaurant);
assertNotNull( newRest );
}
@Test
public void restaurantNotCreatedDueToValidationFailure() {
Restaurant restaurant = new Restaurant();
Mockito.when( restVal.validated(restaurant)).thenReturn( false );
Mockito.when( restDAO.persist(restaurant)).thenReturn( true );
Restaurant newRest = newRestaurant.createRestaurant(restaurant);
Mockito.verify( restVal ).validated(restaurant);
Mockito.verify( restDAO, Mockito.never() ).persist(restaurant);
assertNull( newRest );
}
@Test
public void restaurantNotCreatedDueToPersistenceFailure() {
Restaurant restaurant = new Restaurant();
Mockito.when( restVal.validated(restaurant)).thenReturn( true );
Mockito.when( restDAO.persist(restaurant)).thenReturn( false );
Restaurant newRest = newRestaurant.createRestaurant(restaurant);
Mockito.verify( restVal ).validated(restaurant);
Mockito.verify( restDAO ).persist(restaurant);
assertNull( newRest );
}
Thus, as a summary, if you would want to have greater fun with TDD, make use of mocking as it allows you to simulate some interesting behaviors without the need for writing any code.
[adsenseyu1]
- Confounder Features & Machine Learning Models: Examples - October 2, 2024
- Credit Card Fraud Detection & Machine Learning - September 26, 2024
- Neural Network Types & Real-life Examples - September 24, 2024
I found it very helpful. However the differences are not too understandable for me