ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • TDD processing with examples
    TestMetric 2019. 8. 27. 20:47

    1. Overview

    TDD is a design tool, enabling us to drive some implementation with the help of tests. It validates if that code results in the expected state(state testing) or executes the expected sequence of events(behavior testing). It helps a developer to verify the logic of a piece of the program is correct. Running tests automatically helps to identify software regressions introduced by changes in the source code. Having a high test coverage of your code allows you to continue developing features without having to perform a lot of manual tests.

    1.1 Workflow

    TDD approach first, the test is developed which specifies and validates what the code will do. In simple terms, test cases are created before the code is written. The purpose of TDD is to make the code clearer, simple, and bug-free.

    Test-Driven Development starts with designing and developing tests for every small functionality of an application. TDD instructs developers to write new code only if an automated test has failed. This avoids duplication of code. The full form of TDD is Test-driven development.

    The simple concept of TDD is to write and correct the failed tests before writing a new code (before development). This helps to avoid duplication of code as we write a small amount of code at a time in order to pass tests. (Tests are nothing but requirement conditions that we need to test to fulfill them).

    Test-Driven development is a process of developing and running an automated tests before the actual development of the application. Hence, TDD sometimes also called Test First Development.

    1.2 Where to use

    TDD is Mainly used to maintain long-term stable service.

    2. Process

    1. Add a test.
    2. Run all tests and see if any new test fails.
    3. Write some code.
    4. Run tests and Refactor code.
    5. Repeat.

    2.1 TDD cycle defines

    1. Write a test
    2. Make it run.
    3. Change the code to make it right i.e. Refactor.
    4. Repeat process.

    2.2 Some clarifications about TDD:

    • TDD is neither about "Testing" nor about "Design".
    • TDD does not mean "write some of the tests, then build a system that passes the tests.
    • TDD does not mean "do lots of Testing."

    3. Difference TDD and Traditional Testing

    • With traditional testing, a successful test finds one or more defects. It is the same as TDD. When a test fails, you have made progress because you know that you need to resolve the problem.
    • TDD ensures that your system actually meets requirements defined for it. It helps to build your confidence in your system.
    • In TDD more focus is on production code that verifies whether testing will work properly. In traditional testing, more focus is on test case design. Whether the test will show the proper/improper execution of the application in order to fulfill the requirements.
    • In TDD, you achieve 100% coverage test. Every single line of code is tested, unlike traditional testing.
    • The combination of both traditional testing and TDD leads to the importance of testing the system rather than the perfection of the system.
    • In Agile Modeling (AM), you should "test with a purpose". You should know why you are testing something and what level it need to be tested.

    2. Features

    2.1 Code (or application) under test

    • The code which is tested is typically called the code under test. If you are testing an application, this is called the application under test.

    2.2 Test fixture

    • A fixed state in code which is tested used as input for a test. Another way to describe this is test precondition.
    • For example, a test fixture might be a fixed string, which is used as input for a method. The test would validate if the method behaves correctly with this input.

    2.3 Unit tests and unit testing

    • A piece of code written by a developer that executes a specific functionality in the code to be tested and assert a certain behavior or state
    • A unit test targets a small unit of code
      • A method or a class
    • External dependencies should be removed from unit tests
      • By replacing the dependency with a test implementation or a (mock) object created by a test framework.
    • Not suitable for testing a complex user interface or component interaction.
      • For this, you should develop integration tests.

    2.4 Test coverage

    • The percentage of code which is tested by unit tests

    2.5 Integration tests

    • Aims to test the behavior of a component or the integration between a set of components.
    • The term functional test is sometimes used as a synonym for integration tests.
    • Check that the whole system works as intended for reducing the need for intensive manual tests.
    • Translate your user stories into a test suite
      • Resemble an expected user interaction with the application

    2.6 Performance tests

    • Used to benchmark software components repeatedly.
    • Ensure that the code under test runs fast enough if it's under high load.

    2.7 Behavior and state testing

    • Common
      • Uses mock or stubs of related classes to abstract the interactions with these other classes away afterwards you test the state or the behavior depending on your need.
    • Behavior testing
      • Check if certain methods were called with the correct input parameters
      • Validate interactions
      • Not validate the result of a method call
    • State testing
      • Validate the result

    2.8 Testing frameworks for Java

    • Junit
    • TestNG
    • etc.

    2.9 Where the test be located

    • src/main/java: for Java classes
    • src/test/java: for test classes

    2.10 Which part of the software should be tested

    • Critical and complex parts of your application
    • In general, safe to ignore trivially code
      • getter and setter

    2.11 TDD Cycles

    • Writing tests: define requirements in the form of tests
    • Implementing features: make the tests pass without focusing too much on the elegance of the code
    • Refactoring: improving the code to make it easier to read and maintain while still passing the tests.

     

    3. Examples

    3.1 The First Cycle

    • Implement a naive method
    public class CustomList<E> implements List<E> {
        private Object[] internal = {};
    
        @Override
        public boolean isEmpty() {
            return true;
        }
    }
    • Write the first test case which makes sure that the isEmpty returns true when the list doesn't contain any element.
    @Test
    public void givenEmptyList_whenIsEmpty_thenTrueIsReturned() {
        List<Object> list = new CustomList<>();
     
        assertTrue(list.isEmpty());
    }

    3.2 The second cycle

    • To confirm the isEmpty returns false when the list isn't empty
    @Test
    public void givenNonEmptyList_whenIsEmpty_thenFalseIsReturned() {
        List<Object> list = new CustomList<>();
        list.add(null);
     
        assertFalse(list.isEmpty());
    }
    @Override
    public boolean add(E element) {
        return false;
    }
    @Override
    public boolean add(E element) {
        internal = new Object[] { element };
        return false;
    }
    @Override
    public boolean isEmpty() {
        if (internal.length != 0) {
            return false;
        } else {
            return true;
        }
    }

    3.3 Refactoring

    Refactoring code more elegantly

    @Override
    public boolean isEmpty() {
        return internal.length == 0;
    }

     

    4. References

    https://www.baeldung.com/java-test-driven-list

    https://www.guru99.com/test-driven-development.html

    https://www.vogella.com/tutorials/JUnit/article.html

    https://www.guru99.com/test-driven-development.html

    'TestMetric' 카테고리의 다른 글

    Metric of Performance  (0) 2020.02.26
    Unit Testing vs Integration Testing  (0) 2020.02.23
    Guideline for testing performance  (0) 2019.09.03
    JUnit  (0) 2019.09.01

    댓글

Designed by Tistory.