Software testing

TDD — My Mistakes & How I Improve Them

TDD — My Mistakes & How I Improve Them
Red Green Refactor — Created by the author using https://app.diagrams.net/

I came across this excellent video [1] on TDD. There are some excellent points in this video that resonate with my experience.

I am going to share those points in more detail by adding my experience.

Running tests in isolation

When we write tests, each test should run in isolation & should not impact other tests.

Example # 1 — Testing DAO layers

A typical example would be testing a DAO layer where each test requires a database.

If tests share the same database, this results in some indeterministic behavior and hence results in randomly failing tests.

So, a solution would be to use a separate database for each unit test. Here goes pseudo code.

Pseudocode

1. Start unit test
2. Create a database
3. Populate test data
4. Test functionality
5. Tear down the created database.

Example # 2 — Mocking

We use mocking for testing an object for instance service layerthat relies on an expensive resource say DAO layer communicating with a database.

If you share your mocked object among unit tests, it again results in indeterministic behavior. As a result, we have randomly failed tests.

In the following example, the two tests shareservice as well as a mocked object.

Don’t do this.

class MyServiceSpec extends AnyWordSpec with MockFactory ... {

private val dao: MongodbProductDAO = mock[MongodbProductDAO]
private val myService = new MyService(dao)

"MyService" should {
"my first test" in { ... }
"my second test" in { ... }
}

}

Do this instead.

class MyServiceSpec extends FixtureAnyWordSpec with MockFactory with Matchers {

override type FixtureParam = MySerivce

override def withFixture(test: OneArgTest): Outcome = {
withFixture(
test.toNoArgTest(
new MySerivce(mock[MongodbProductDAO])
)
)
}

"MyService" should {
"my first test" in { service => ... }
"my second test" in { service => ... }
}
}

Each test will have its own service object and hence mocked object.

Red-green-refactor

You might be wondering that red-green-refactor = test driven development. I would say yes, but I learned something new from this video [1].

Here it goes.

1. Write a behavior that fails even without writing any 
implementation -> (RED).
2. Write (even ugly) code (without caring about design patterns etc) to
make the behavior working -> (GREEN)
3. Do refactoring. This is a cleanup process & using design patterns
comes here.

It means:

  1. It’s okay to write ugly code to pass our given behavior and clean the code (refactoring / using design patterns etc) later.
  2. (IMPORTANT) Refactoring should not break our test. If it does, then there is something seriously wrong with either implementation or a behavior.

Testing behaviors & not implementations

As the name suggests, our test should not be tightly coupled with the implementation details.

It may sound very obvious to us, but trust me I was making this mistake too.

If I was testing behaviors, I would not have tested private methods. You will find a discussion about testing private methods here.

The more we add tests to test implementation details, the more we add tight coupling between test & implementation details. It means when we refactor code, our tests will start to fail. This is a bad design, in my opinion.

Slow test execution means slow feedback

Speed in tests matters. Slow test execution means slow feedback i.e whether a given solution works perfectly without breaking other tests.

Here I don’t (necessarily) mean individual tests but when the whole CICD pipeline works for your given solution.

A story about slow test execution

At work, we use generators for generating fake data. This slows down test execution because it runs the same test for different data sets.

This means if we have 2 tests and each runs 4 times then there will be total 8 executions. More executions require more time.

This slows down the whole CICD pipeline and hence results in slow feedback.

Resource

[1] https://www.youtube.com/watch?v=EZ05e7EMOLM

Thanks for reading. If you have any questions, please feel free to ask in the comment section.

If you enjoyed this post, you might also like the following posts.

Want to connect?

Facebook | LinkedIn | Twitter

--

--

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
Anas Anjaria

Anas Anjaria

226 Followers

Software Engineer | Mostly writing technical articles and sharing my professional experience. https://anasanjaria.bio.link