Unit tests towards better OOP

Thanks Myfuture.com, https://www.flickr.com/photos/myfuturedotcom/6053042920

Typical Shopping Cart

This article is about a shopping cart on a typical online shop.

Let’s imagine it

We’ll have to save identification of the product and the amount, it’s easy.

Let’s forget how the cart is saved.

Let’s focus on data we need to display!

1st Trivial Test

Of course — what do we even test?

We have to start somehow, and trivial test is so obvious, we understand it without thinking.

We use a plain array because it is the most straight-forward representation in PHP. In the real project we would use a read DTO. We’ll keep the plain array in code for simplicity in this article.

Test Phases

Anyway even this trivial test contain logical parts we’ll repeat again in more complex tests.

System setup

$cart = new Cart();

Action

$cart->add('ab123');

Expected result

$expected = [
'ab123' => 1,
];

Outer point of view to object

$actual = $cart->read();

Assertion

Assert::assertSame($expected, $actual);

2nd More Same Products

Setup -> Actions -> Expected result -> Outer point of view -> Assertion.

Let’s focus on the expected part. We often hear that we should focus on business logic, and we often struggle to isolate it.

$expected = [
'ab123' => 2,
];

This is the business logic!

Something happens, and we don’t care how it’s done. We care what is done. And that is expressed by expected phase.

3rd Removing Product

Trivial, again. We fill the cart, and after removing, we expect the cart is empty.

I don’t recommend to assert what is in the cart after line 3. This is tested in a different test, and asserting the content even in this test would mean we have to change more tests when we change the logic. Also the test would be more complex and wouldn’t express obviously what it tests.

4th Removing Not Existing Product

What should happen?

Maybe we’ll ignore this situation. Maybe we’ll throw an exception. Either way the expected phase forces us to think about this case and forces us to make a decision.

Implementation

We don’t have to invent methods — the interface of the class — methods are defined by tests.

Implementation is, again, quite easy.

The goal of Outer point of view is that we can refactor/change/replace internals of the class without any restrictions. This is the biggest strength.

We can use it when refactoring the class for

  • Maximum performance
  • Easy persistence
  • Easy extensibility

“Make the change easy, then make the easy change”

Kent Beck

The Outer point of view allows us making changes.

Real life example

Shopping cart is a simple example to demonstrate steps in isolation. But this article would be just another trivial “Hello world” article without complex real life example.

Customer in CMS

Customer in our CMS might have multiple contacts. But one of his contacts is a special contact that represents the customer’s bio. If we change customer’s bio, the contact is changes as well.

So… how will we solve it? Will we add a special flag to the contact?
No! We, again, think how to store it.

Let’s start with tests first.

We described now the outer point of view to the object, let’s implement it.

Do we have only one option for the implementation? No! That’s the strength of tests + outer point of view. We might decide for different implementation because adding different features will be simpler.

Interface of the class didn’t change, tests didn’t change, all tests passes, but the logic behind the scenes is different.

The first implementation is easier to understand for me.

The second implementation is faster for reading contacts — there is no merging of arrays.

TL;DR

Writing tests forces us to

  • Behavior (Expected)
    $expected = ...;
  • Encapsulation (Outer point of view to object)
    $cart->add(...);
    $cart->read();

Encapsulated behavior is a sign of a great OOP.

--

--

--

Carvago is a large tech company and this publication focuses on topics related to development, design, analysis and architecture of our systems.

Recommended from Medium

Kubernetes lab 104 ReplicaSet with Yaml

Say Agile One More Time

Agile implementation for a company like Zomatio

Refactoring: Being glad of your past self

A Unit Tests Checklist Poster

[LeetCode] (Easy) 83. Remove Duplicates from Sorted List

Extra-Laser-Unity #01 Building a Space Fighter with Colors

Where does your “innovation” happen?

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Svaťa Šimara

Svaťa Šimara

Developer interested in Domain-Driven Design & Modeling

More from Medium

How To…Increasing your Database Performance

Generating SDKs for your API

How to Write a Strategy Pattern using Functional Programming Principles?

What is the clean code? (Part2)