Test-Driven Android Development, Part 2

Hossein Abbasi
AndroidPub
Published in
8 min readNov 30, 2018

--

Image by dailybackgrounds.com

In this article series, we’re going to follow this road-map:

  1. Fundamentals of Test Driven Development(TDD)
  2. Designing for Test
  3. Introduction to Unit Testing
  4. Behavior-Driven Development(BDD)
  5. Add-ins & Plug-ins
  6. Testing Beyond the Unit Test

If you haven’t read the previous series, it would be nice to take a look.

Designing for Test

  • Why do we use DTO?
  • Why do we have different layers of classes?
  • And see how a good Object-Oriented-Design leads to a good Test-Driven-Design and vice-versa.

Object-Oriented-Design:

Object-oriented design is the process of planning a system of interacting objects for the purpose of solving a software problem.

The 5 Basic Concepts of Object Oriented Design are:

  1. Encapsulation: It’s a mechanism of wrapping the data (variables) and code acting on the data (methods) together as a single unit. In encapsulation, the variables of a class will be hidden from other classes, and can be accessed only through the methods of their current class. Therefore, it is also known as data hiding. To achieve encapsulation in Java: a. Declare the variables of a class as private. b. Provide public setter and getter methods to modify and view the variables values.
  2. Data Protection: The ability to protect some components of the object from external entities. This is realized by language keywords to enable a variable to be declared as private or protected to the owning class.
  3. Inheritance: The ability for a class to extend or override functionality of another class. The so called child class has a whole section that is the parent class and then it has it’s own set of functions and data.
  4. Interface: A definition of functions or methods, and their signatures that are available for use to manipulate a given instance of an object. In other word, a contract that indicates what a class will do. One of differences between class and interface is, a class describes the attributes and behaviors of an object, and an interface contains behaviors that a class implements.
  5. Polymorphism: The ability to define different functions or classes as having the same name but taking different data types. In other word, Polymorphism is the ability of an object to take on many forms. The most common use of polymorphism in OOP occurs when a parent class reference is used to refer to a child class object.

Object-Oriented-Design best practices:

  • Each class should do one thing and do it well.
  • Avoid very long classes. These classes are hard to test and it’s hard to make that class reusable.

Data Transfer Object(DTO):

  • It’s a Plain Old Java Object(POJO).
  • It doesn’t have to extends anything.
  • It doesn’t have any dependencies on anything.

We’re using DTO, because as we have these layers: a. DAO, b. Business Logic, c. User Interface, we need to transfer data from one to the other independent of manner.

Traditional layers:

  • Persistence: To store data to some kind of data store.
  • Data Access Object(DAO): These are specific to entities in the persistence layer.
  • Business Logic(Service layer): Play rules on data which comes form DAO. For example check if albums are more than 5. The nice thing about having these layers separated is we can reuse those DAO concepts across different service layers.
  • UI: On top of service layer, and for example searching albums; It talks to service layers, service layers talk to Data Access Object, and DAO talks to Persistence layer.
  • DTO: It’s the piece that ties everything together. It’s often a return type of fetch method, and a parameter of a insert/update/delete method.

Stub, Mock, Fake:

It’s an object that holds predefined data and is a controllable replacement for an existing dependency(or collaborator) in the system. By using a stub, you can test your code without dealing with the dependency directly.

In other word, it’s a fake data that you can use to test or develop your code against until you (or the other party) is ready to present/receive real data.

In Roy Osherove’s “The Art of Unit Testing” book, section 3.1, “Introducing stubs”:

A stub is a controllable replacement for an existing dependency (or collaborator) in the system. By using a stub, you can test your code without dealing with the dependency directly.

And defines the difference between stubs and mocks as:

The main thing to remember about mocks versus stubs is that mocks are just like stubs, but you assert against the mock object, whereas you do not assert against a stub.

Fake is just the name used for both stubs and mocks. For example when you don’t care about the distinction between stubs and mocks.

The way Osherove’s distinguishes between stubs and mocks, means that any class used as a fake for testing can be both a stub or a mock. Which it is for a specific test depends entirely on how you write the checks in your test.

  • When your test checks values in the class under test, or actually anywhere but the fake, the fake was used as a stub. It just provided values for the class under test to use, either directly through values returned by calls on it or indirectly through causing side effects (in some state) as a result of calls on it.
  • When your test checks values of the fake, it was used as a mock.

For more information, you can check this article by Michal Lipski.

DTO and Clean Architecture:

I want to quote directly from Mr. Juan Carlos Eduardo which in this case, I’m agree with:

Ideally, DTOs will match your persistence repositories (aka, your database tables).

But your business classes are not necessarily a match. You might need additional classes , or separated, or joined classes to what you have in database. If your application is small, you might not really see this kind of problems, but in medium to large applications, this will happen often.

Another thing is that DTOs are part of the domain of whatever it is that deals with persistence, while your Business Layer should know nothing about them.

For more information, please take a look at this StackExchange discussion.

I’m just saying that in unlike our approach in one of my articles about Clean Architecture, I’m going to use just DTO classes across layers; By layers, I’m not talking about Domain, Data, and Presentation layers. I’m talking about Data Access layer, Service layer, and User Interface layer.

So, because it brings data to each layers and those layers have different dependencies each self, our DTO has to have few to zero dependencies.

For rest of article series, I’m going to code on this repository, which of course might be changed during each next series:

Step by step I’m going to talk about each parts of the project.

Note: The snipped code images created by this brilliant website.

First, we create our DTO class:

Then we create our contract to fetch data from server(DAO interface):

And then implement this contract:

Now, we’re going to create our service layer. This is a place for any kind of business logic and also for aggregating our DAOs together.

Note: Just keep in mind that we’re going to implement this project as simple as possible. For example in above implementation it’s possible to inject our AlbumDao, but the focus of these articles are TDD.

Another point is we set the type of albumDao to AlbumDao, the interface; Not the class itself. It’s just because the object(AlbumDaoImpl) can changes later to something else, as long as the something else implement our interface.

For more information, please take a look at Dependency inversion principle in S.O.L.I.D principles.

Using that album service inside our activity, looks like:

What is If Test: It’s a decision structure which can value true or false or multiple conditions. It can be written in one class or can simulate same thing by using good OOP by using super class and sub class structure.

If it’s hard to write unit testing for these If Tests, it means:

  • That logic is in a wrong class
  • We have a big class, while we could use sub classes and a parent. So, when in future a feature wants to be added to our application, we easily add it as a sub class.

Our attempt is to removing these If Tests to make it possible that our UI may does not have to change; Makes our program much feature-proof.

Imagine my colleague on the back-end side doesn’t finish his work yet and we don’t have a ready live API to use. You’re happy, huh? 😆 but let’s be honest, we can continue to programming without it, with the help of Stub!

Our AlbumDaoStubImpl becomes something like this:

Now, just replace AlbumDaoImpl() with AlbumDaoStubImpl() inside AlbumServiceImpl class.

See? I’ve just replaced the previous object with the new one. Let’s repeat the point I’ve mentioned earlier again:

We set the type of albumDao to AlbumDao, the interface; Not the class itself. It’s just because the object(AlbumDaoImpl) can changes later to something else, as long as the something else implement our interface.

What’s Next?

On the next article, we’ll go through “Introduction to Unit Testing”.

Thank you for taking your precious time to reading this article. Please clap your 👏 and help others find this article too.

References:

--

--