Shift left testing with TDD- Part II

Shift left testing with TDD- Part II

We have seen what is TDD in earlier article. Now lets see what are the 3 laws of TDD by Robert C Martin who is known by name Uncle Bob.

Uncle Bob describes TDD with three rules:

  1. You are not allowed to write any production code unless it is to make a failing unit test pass - This means you will only write enough code to make failing unit test pass. No extra logic, no extra gold plating. We focus on one test at a time , hence write a code to satisfy that particular unit test only. So once your failing test pass, stop adding more production code. You will add another failing unit test and then to satisfy it, you will add code. Rule is simple, no production code to be added without a unit test.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures - You write one unit test at a time and at beginning it will be a failing test as that logic is not yet added in production code. If your test is very first unit test for that class , even the class is not yet written , neither the function, then you will get compilation error in test and it is also considered as a failing test. Hence to fix compilation error, you add skeleton of class and method and your compilation error is fixed. But still your test is failing as your code is not yet added . Hence you will add code to pass that test. Until this test pass, you are not going to add any more test. You will add one test at a time. If you add a test and it does not fail , it means the logic is already in place and probably you might have duplicate test case written. If its not a failing test, then its not needed.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test - You might think rule 3 is similar to rule 1. But read carefully, here he wants to tell that you will add sufficient code to pass only one failing test. Suppose you are refactoring and post refactoring you run all the tests and you found that 3 tests are failing post your refactoring. Here your focus should be to fix one failing test at a time. Fix it, run it and then pick up second failing test. Don't try to fix all failing tests at once. But make sure you execute all the test cases throughout this exercise to ensure your changes are not breaking other logic as your tests are your safety net.

Lets focus on F.I.R.S.T principles now.

F.I.R.S.T Principles of good Unit Test:

F.I.R.S.T is acronym for Fast, Isolated, Repeatable, Self-validating and Timely. Lets see them one by one:

Fast: Your unit tests should be fast enough else they will slow down your development and eventually deployment of code. Imagine you are working on a big application with number of classes and you are writing unit tests for each unit of code and you end up writing 2000 unit tests. If your unit tests are taking like 200 milliseconds to run , for entire suite will take around 6.5 minutes to run. You will still say that its fast enough, but you have to run it in your development environment multiple times of day , then it will eat lots of your bandwidth.

So question is why unit test becomes slow and how we can make sure they are fast?

Every unit test has 3 parts-

  1. Arrange: Here you arrange data required for input parameter, initialize class whose method we are testing.
  2. Act: Here you invoke actual method you are testing by passing those input parameters and capture any return values
  3. Assert: Here you assert the result of test by validating if it is expected result or not.

Ideally unit test is very fast to execute. In a scenario where your code has dependency with database or webservice or network etc. and you are making call to read db or webservice or socket connection in your unit test, then it will slow down your test. Hence recommended practice is to mock those dependencies to execute it faster. These type of testing is also called integration testing with TDD where we are trying to validate if your unit of code works well while interacting with other dependencies. So if you avoid making call to real dependent objects and mock it, it will not slow down your unit test.

The refactoring rule also applies to unit test cases. Unit test cases should not have unwanted code, it should be simple and small. As per rule , one unit test should validate only one scenario and ideally should have only one assert. You may have more than one asserts though depending on some exceptional situation. If you follow these rules, your tests will execute within fraction of a second .

Isolated: Your unit test case should not have dependency on another unit test case. Every unit test case should be unique and should be able to execute independently and pass even if you run it in any sequence. If you make your test independent, it becomes easy for your test to focus only on a small amount of behavior. It even helps programmer to fix issue in the code if any test fails as that test's intention is to test only one scenario, not more than that. You can apply the single responsibility principle for your test cases and make sure that there is only one reason for your test to fail not more than that.

Repeatable: Repeatable test is such test, which will produce same result every time you run it. Even if you run it in your local dev environment, SIT, UAT anywhere, it should produce same result. If your test is producing different result in every run, its not a good unit test. If your tests are isolated from external dependencies with mock, they become repeatable. If you absolutely need to do integration test with your unit test with a DB, there are options to use in-memory databases in your test. If you follow these rules, your tests are isolated and hence becomes repeatable.

Self-validating: Self -validating test means , the test must be able to validate the output from unit of code . Means, your test should determine if your unit of code works correct and the test fail or pass. No manual interpretation should be required to validate the result. The asserts written in test should be able to do this self validation.

Don't depend on any manual configuration to run test to validate result. Everything should be automated like setup(arrange part), invocation of method(act part) and validation of result(assert part). You should keep the data ready to validate results of test.

Timely: You should write your test just before writing your production code. Practically , programmers can write unit test cases at any time, but it does not make sense. They themselves wont remember what their code is doing, to test it with unit test cases. There should not be any time gap between your test and production code. So best practice is test driven development , where you write test and immediately write code to satisfy that test. This is called ,timely test. The benefit is, you get immediate feedback if your code is working as expected or not . This way you can identify bugs immediately and can fix those and avoid spilling over them to next test cycle.

If every programmer follow the 3 rules and F.I.R.S.T principles while writing unit test cases, the quality is the only outcome !!

That's it for today. Stay tuned for tomorrow ...




VARSHA GURAV

HRBP Pigments Industrial Products

3 年

Nicely articulated ????

Rushikesh Pisal

Senior Associate at JPMorgan Chase & Co.

3 年

Very useful.!! Thanks.

Dr. Srinagesh Chatarajupalli

Career Coaching For Scrum Masters, Senior Scrum Masters, RTEs & Agile Coaches, Agile Product Owners, Product Managers, Agile Project Managers, Agile Delivery Managers| Ph. D in Agile Guided by IIML & IIMK | SAFe SPC |

3 年

Well said

Krishna Padave

Founding Member @Watermelon Software Inc.

3 年

Insigthful. Thanks Mamta

Suparna G.

Transformational marketing leader | Business Storyteller | Brand EQ Specialist | 0 to 1 as well as 10 to 100 journey experienced | Founding Member FLS | Strategic alliances at Sirrus.AI, Ziki

3 年

I loved reading it and found the first principles really useful

要查看或添加评论,请登录

Mamata Raote的更多文章

  • YAGNI ("You Aren't Gonna Need It")

    YAGNI ("You Aren't Gonna Need It")

    Today let's talk about YAGNI principle which emphasizes on simple design. What YAGNI means? YAGNI is acronym for "You…

    2 条评论
  • Keep It Simple and Stupid(K.I.S.S) principle

    Keep It Simple and Stupid(K.I.S.S) principle

    “It seems that perfection is attained not when there is nothing more to add, but when there is nothing more to remove.”…

    2 条评论
  • Don't Repeat Yourself(DRY) Principle

    Don't Repeat Yourself(DRY) Principle

    Today lets talk more about "Don't Repeat Yourself (DRY) " principle. This principle is known and applied from quiet…

    4 条评论
  • Understand Technical Debt

    Understand Technical Debt

    What is Technical Debt? The term technical debt is coined by Agile Manifesto co-author Ward Cunningham. Tech Debt…

  • Four Rules Of Simple Design

    Four Rules Of Simple Design

    We have seen SOLID principles of design. There is another interesting set of simple design rules defined by Kent Beck…

  • Dependency Inversion Principle(DIP)

    Dependency Inversion Principle(DIP)

    Today lets look into last SOLID principle i.e Dependency Inversion Principle.

    2 条评论
  • Interface Segregation Principle

    Interface Segregation Principle

    Today lets talk about "Interface Segregation Principle". This principle relates to the problem of a fat interface which…

    2 条评论
  • Liskov Substitution Principle

    Liskov Substitution Principle

    We have seen "Open Closed Principle" in previous article. This principle helps us to maintain our code , make reusable…

  • Open Closed Principle (OCP)

    Open Closed Principle (OCP)

    Last week we have seen what are SOLID principles and how to honor "Single Responsibility Principle". Today we will look…

  • Introduction to SOLID Principles

    Introduction to SOLID Principles

    Simple Design and Coding standards are principles of Extreme Programming. We want to write clean code which can be…

    1 条评论

社区洞察

其他会员也浏览了