Citizendia

Test-Driven Development (TDD) is a software development technique consisting of short iterations where new test cases covering the desired improvement or new functionality are written first, then the production code necessary to pass the tests is implemented, and finally the software is refactored to accommodate changes. Software development is the translation of a user need or marketing goal into a Software product A test case in Software engineering is a set of conditions or variables under which a tester will determine if a Requirement or Use case upon The availability of tests before actual development ensures rapid feedback after any change. Practitioners emphasize that test-driven development is a method of designing software, not merely a method of testing. Software engineering is the application of a systematic disciplined quantifiable approach to the development operation and maintenance of Software.

Test-Driven Development is related to the test-first programming concepts of Extreme Programming, begun in the late 20th century, but more recently is creating more general interest in its own right. Extreme Programming (or XP) is a Software engineering methodology (and a form of Agile software development) Proponents of Extreme Programming and agile [1]

Along with other techniques, the concept can also be applied to the improvement and removal of software defects from legacy code that was not developed in this way [2]. A software bug (or just “bug” is an error flaw mistake Failure, fault or “undocumented feature” in a Computer program that prevents it

Contents

Requirements

Test-driven development requires that an automated unit test, defining requirements of the code, is written before each aspect of the code itself. Test automation is the use of Software to control the execution of tests the comparison of actual outcomes to predicted outcomes the setting up of test preconditions These tests contain assertions that are either true or false. In Computer programming, an assertion is a predicate (ie a true–false statement placed in a program to indicate that the developer thinks that the Running the tests gives rapid confirmation of correct behaviour as the code evolves and is refactored. Testing frameworks based on the xUnit concept (see the list of unit testing frameworks for an exhaustive list) provide a mechanism for creating and running sets of automated test cases. Various code-driven testing frameworks have come to be known collectively as XUnit. This page is a list of tables of code-driven Unit testing frameworks for various Programming languages Some of these are based on XUnit, but not all of them are

Test-Driven Development Cycle

The following sequence is based on the book Test-Driven Development by Example [3], which many consider to be the canonical source text on the concept in its modern form. Test Driven Development By Example is a book about a Software development technique by Kent Beck.

1. Add a test

In test-driven development, each new feature begins with writing a test. This test must inevitably fail because it is written before the feature has been implemented. In order to write a test, the developer must understand the specification and the requirements of the feature clearly. This may be accomplished through use cases and user stories to cover the requirements and exception conditions. A use case is a description of a system’s behaviour as it responds to a request that originates from outside of that system A user story is a software system Requirement formulated as one ortwo sentences in the everyday language of the user This could also imply an invariant, or modification of an existing test. This is a differentiating feature of test-driven development versus writing unit tests after the code is written: it makes you focus on the requirements before writing the code, a subtle but important difference.

2. Run all tests and see the new ones fail

This validates that the test harness is working correctly and that the new test does not mistakenly pass without requiring any new code.

The new test should also fail for the expected reason. This step tests the test itself, in the negative. A "negative test" is something familiar to testers, to make sure a feature fails when it should fail (e. g. bad input data). It typically follows or is "paired" with one or more "positive tests" that make sure things work as expected (e. g. good input data). ("Make sure it works, then change one thing to make it break and make sure it breaks. ") The entire suite of unit tests act to serve this need, cross-checking each other to make sure "negative tests" fail for the expected reasons.

This technique avoids the syndrome of writing tests that always pass, and therefore aren't worth much. Running the new test to see it fail the first time is a vital "sanity check".

3. Write some code

The next step is to write some code that will cause the test to pass. The new code written at this stage will not be perfect and may, for example, pass the test in an inelegant way. That is acceptable because later steps will improve and hone it.

It is important that the code written is only designed to pass the test; no further (and therefore untested) functionality should be predicted and 'allowed for' at any stage.

4. Run the automated tests and see them succeed

If all test cases now pass, the programmer can be confident that the code meets all the tested requirements. This is a good point from which to begin the final step of the cycle.

5. Refactor code

Now the code can be cleaned up as necessary. By re-running the test cases, the developer can be confident that refactoring is not damaging any existing functionality. The concept of removing duplication is an important aspect of any software design. In this case, however, it also applies to removing any duplication between the test code and the production code — for example magic numbers or strings that were repeated in both, in order to make the test pass in step 3. In Computer programming, the term magic number has multiple meanings

Repeat

Starting with another new test, the cycle is then repeated to push forward the functionality. The size of the steps can be as small as the developer likes, or get larger if s/he feels more confident. If the code written to satisfy a test does not fairly quickly do so, then the step-size may have been too big, and maybe the smaller testable steps should be used instead. When using external libraries it is important not to make increments that are so small as to be effectively merely testing the library itself [1], unless there is some reason to believe that the library is buggy or is not sufficiently feature complete to serve all the needs of the main program being written.

Development style

There are various aspects to using test-driven development, for example the principles of "Keep It Simple, Stupid" (KISS) and "You Ain't Gonna Need It" (YAGNI). KISS redirects here See also. For other uses see Kiss (disambiguation. In Software engineering, YAGNI, short for 'You Ain't Gonna Need It' suggests to programmers that they should not add functionality until it is necessary By focusing on writing only the code necessary to pass tests, designs can be cleaner and clearer than is often achieved by other methods[3]. In Test-Driven Development by Example Kent Beck also suggests the principle "Fake it, till you make it".

To achieve some advanced design concept (such as a Design Pattern), tests are written that will generate that design. The code may remain simpler than the target pattern, but still pass all required tests. This can be unsettling at first but it allows the developer to focus only on what is important.

Test-driven development requires the programmer to first fail the test cases. The idea is to ensure that the test really works and can catch an error. Once this is shown, the normal cycle will commence. This has been coined the "Test-Driven Development Mantra", known as red/green/refactor where red means fail and green is pass.

Test-driven development constantly repeats the steps of adding test cases that fail, passing them, and refactoring. Receiving the expected test results at each stage reinforces the programmer's mental model of the code, boosts confidence and increases productivity.

Advanced practices of test-driven development can lead to Acceptance Test-driven development [ATDD] where the criteria specified by the customer are automated into acceptance tests, which then drive the traditional unit test-driven development [UTDD] process. This process ensures the customer has an automated mechanism to decide whether the software meets their requirements. With ATDD, the development team now has a specific target to satisfy, the acceptance tests - which keeps them continuously focused on what the customer really wants from that user story.

Benefits

A 2005 study found that using TDD meant writing more tests and, in turn, programmers that wrote more tests tended to be more productive. [4] Hypotheses relating to code quality and a more direct correlation between TDD and productivity were inconclusive. [5]

Programmers using pure TDD on new ("greenfield") projects report they only rarely feel the need to invoke a debugger. In Software engineering Jargon, a greenfield is a project which lacks any constraints imposed by prior work A debugger is a Computer program that is used to test and Debug other programs Used in conjunction with a Version control system, when tests fail unexpectedly, reverting the code to the last version that passed all tests may often be more productive than debugging. Revision control (also known as version control (system (VCS, source control or (source code management (SCM) is the management of multiple revisions [6][7]

Test-driven development can help to build software better and faster. It offers more than just simple validation of correctness, but can also drive the design of a program. By focusing on the test cases first, one must imagine how the functionality will be used by clients (in this case, the test cases). Therefore, the programmer is only concerned with the interface and not the implementation. This benefit is complementary to Design by Contract as it approaches code through test cases rather than through mathematical assertions or preconceptions. Design by Contract, DbC or Programming by Contract is an approach to designing Computer software.

The power test-driven development offers is the ability to take small steps when required. It allows a programmer to focus on the task at hand as the first goal is to make the test pass. Exceptional cases and error handling are not considered initially. Tests to create these extraneous circumstances are implemented separately. Another advantage is that test-driven development, when used properly, ensures that all written code is covered by a test. This can give the programmer, and subsequent users, a greater level of trust in the code.

While it is true that more code is required with TDD than without TDD because of the unit test code, total code implementation time is typically shorter. [8] Large numbers of tests help to limit the number of defects in the code. The early and frequent nature of the tests helps to catch defects early in the development cycle, preventing them from becoming endemic and expensive problems. Eliminating defects early in the process usually avoids lengthy and tedious debugging later in the project.

TDD can lead to more modularized, flexible, and extensible code. This effect often comes about because the methodology requires that the developers think of the software in terms of small units that can be written and tested independently and integrated together later. This leads to smaller, more focused classes, looser coupling, and cleaner interfaces. The use of the Mock Object design pattern also contributes to the overall modularization of the code because this pattern requires that the code be written so that modules can be switched easily between mock versions for unit testing or "real" version for deployment. In Object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways

Limitations

  1. TDD is difficult to use in situations where full functional tests are required to determine success or failure. It is much harder to do test-first functional testing, as the system needs to be brought up to run a test. Examples of these are GUIs (graphical user interfaces), programs that work with relational databases, and those that work (or fail to work) in different network configurations. A relational database is a Database that groups data using common attributes found in the data set Test frameworks for many such systems are available, however the focus has to be on writing tests during/after development, rather than before.
  2. Management support is essential. Without the entire organization believing that Test-Driven Development is going to improve the product, management will feel that time spent writing tests is wasted [1].
  3. Testing has historically been viewed as a lower status position than developer or architect. This can be seen in products such as Visual Studio 2005, whose Architect Edition [2] lacked the testing facilities that the Testing Edition offered [3].
  4. The tests themselves can become part of the maintenance overhead of a project. Badly written tests, that search for hard-coded (rather than shared) error strings, or which are themselves prone to failure, are expensive to maintain. There is a risk that a test that generates false positives will be ignored, so that when it does finally detect a real failure, this will not be detected. It is critical to write tests for low/easy maintenance.

Code Visibility

There are three kinds of testing code: black box, white box, and glass box. Black box testing takes an external perspective of the test object to derive test cases Compare with Black box testing. White box testing (aka clear box testing glass box testing or structural testing uses an internal perspective Compare with Black box testing. White box testing (aka clear box testing glass box testing or structural testing uses an internal perspective Black box unit tests functionality at the interface boundaries. Nearly all unit tests are structured as black-box tests, because it guarantees software modularity, and forces an emphasis on the interface of the module. White box testing occurs when your tests can both observe and mutate state belonging to the software under test. These kinds of tests are strongly discouraged, because subtle bugs can appear if the test itself is buggy. Glass box testing occurs when your tests can only observe, but not mutate, the state belonging to the production code. Applications of glass box testing include hardware-level verification of a function's output. For example, verifying a skip-list's links are properly set is vital to the successful and bug-free operation of a skip-list's implementation.

Test-suite code clearly has to be able to access the code it is testing. In almost every case imaginable, this access occurs through the published interface of function, procedure, or method calls. The use of "mock objects" ensures information hiding remains intact, guaranteeing a total separation of concerns. In Computer science, the principle of information hiding is the hiding of design decisions in a computer program that are most likely to change thus protecting In Computer science, separation of concerns ( SoC) is the process of breaking a Computer program into distinct features that overlap in functionality as

Unit test code for TDD is almost never written within the same project or module as the code being tested. Modular programming is a software design technique that increases the extent to which software is composed from separate parts called modules By placing tests in a separate module or library, the production code remains pristine. Placing the TDD code inside the same module would fundamentally alter the production code. Use of conditional compilation directives can introduce subtle bugs.

Some may argue that using strict black box testing does not provide access to private data and methods. This is intentional; as the software evolves, you may find the implementation of a class changes fundamentally. Remember a critical step of test-driven development is to refactor. Refactoring may introduce changes which adds or removes private members, or alters an existing member's type. These changes ought not break existing tests. Unit tests that exploit glass box testing are highly coupled to the production software; changing the implementation of a class or module may mean you must also update or discard existing tests, things which should never have to occur. For this reason, glass box testing must be kept to the minimum possible. White box testing should never be used in test-driven development.

In all cases, thought must be given to the question of deployment. The best approach is to develop your software so that you have three major components. The first major component is the unit test runner application framework itself. The second is the main entry module for the production logic. Both of these modules would link (preferably dynamically) to one or more libraries, each implementing some or all of the business logic under development. This guarantees total modularity and is thoroughly deployable.

Fakes, mocks and integration tests

Unit tests are so-named because they test one unit of code. Whether your code has hundreds of unit tests or only five is irrelevant. A test suite should never cross module boundaries in a program. Doing so runs the risk of introducing extensive delays, or worse, inadvertently turning your unit tests into integration tests. The latter is particularly problematic, since if any one module fails in a chain of inter-related modules, your test will fail, and there will be no indication as to why or where it failed. This defeats the purpose of unit testing!

This appears to lead to a problem when the code under development relies on a database or a web service or any other external process or service. This is not a problem, however, but an opportunity and a driving force to design more modular, more testable and more re-usable code. Two steps are necessary:

  1. Whenever external access is going to be needed in the final design, an interface should be defined that prescribes the access that will be available. Interface generally refers to an abstraction that an entity provides of itself to the outside
  2. The interface should be implemented in two ways, one of which really accesses the external process, and the other is a fake or mock object. In Object-oriented programming, mock objects are simulated objects that mimic the behavior of real objects in controlled ways Fake objects need do little more than add a message such as "Person object saved" to a trace-log or to the console, if that. In Software engineering, tracing is a specialized use of logging to record information about a program's execution Fake objects are also known as stub objects. Mock objects differ in that they themselves contain test assertions that can make the test fail, for example, if the person's name and other data are not valid. Fake and mock object methods that return data, ostensibly from a data store or user, can help the test process by always returning the same, realistic data that the tests can rely upon.

The disadvantage of this approach is that the actual database or other external-access code is never tested by the TDD process. This omission must be avoided: other tests are needed that instantiate the test-driven code with its 'real' implementations of the interfaces discussed above. Many developers find it useful to keep these tests quite separate from the TDD unit tests, and refer to them as integration tests. There will be fewer of them, and they need be run less often than the unit tests. They can nonetheless be implemented using the same testing framework, for example xUnit. Various code-driven testing frameworks have come to be known collectively as XUnit.

Integration tests that alter any persistent store or database should be careful always to leave them in a state ready for re-use, even if any test fails. This can be achieved using some combination of the following techniques where relevant and available to the developer:

Frameworks such as jMock exist to make the process of creating and using mock objects easier.

References

  1. ^ a b Newkirk, JW and Vorontsov, AA. Test-Driven Development in Microsoft . NET, Microsoft Press, 2004.
  2. ^ Feathers, M. Working Effectively with Legacy Code, Prentice Hall, 2004
  3. ^ a b Beck, K. Test-Driven Development by Example, Addison Wesley, 2003
  4. ^ Erdogmus, Hakan; Morisio, Torchiano. On the Effectiveness of Test-first Approach to Programming. Proceedings of the IEEE Transactions on Software Engineering, 31(1). January 2005. (NRC 47445). Retrieved on 2008-01-14. 2008 ( MMVIII) is the current year in accordance with the Gregorian calendar, a Leap year that started on Tuesday of the Common Events 1129 - Formal approval of the Order of the Templar at the Council of Troyes.  “We found that test-first students on average wrote more tests and, in turn, students who wrote more tests tended to be more productive. ”
  5. ^ Proffitt, Jacob. TDD Proven Effective! Or is it?. Retrieved on 2008-02-21. 2008 ( MMVIII) is the current year in accordance with the Gregorian calendar, a Leap year that started on Tuesday of the Common Events 362 - Athanasius returns to Alexandria. 1245 - Thomas, the first known Bishop of Finland  “So TDD's relationship to quality is problematic at best. Its relationship to productivity is more interesting. I hope there's a follow-up study because the productivity numbers simply don't add up very well to me. There is an undeniable correlation between productivity and the number of tests, but that correlation is actually stronger in the non-TDD group (which had a single outlier compared to roughly half of the TDD group being outside the 95% band). ”
  6. ^ Clark, Mike. Test-Driven Development with JUnit Workshop. Clarkware Consulting, Inc. . Retrieved on 2007-11-01. Year 2007 ( MMVII) was a Common year starting on Monday of the Gregorian calendar in the 21st century. Events 996 - Emperor Otto III issues a deed to Gottschalk Bishop of Freising which is the oldest known document using the name Ostarrîchi  “In fact, test-driven development actually helps you meet your deadlines by eliminating debugging time, minimizing design speculation and re-work, and reducing the cost and fear of changing working code. ”
  7. ^ Llopis, Noel (20 February 2005). Stepping Through the Looking Glass: Test-Driven Game Development (Part 1). Games from Within. Retrieved on 2007-11-01. Year 2007 ( MMVII) was a Common year starting on Monday of the Gregorian calendar in the 21st century. Events 996 - Emperor Otto III issues a deed to Gottschalk Bishop of Freising which is the oldest known document using the name Ostarrîchi  “Comparing [TDD] to the non-test-driven development approach, you're replacing all the mental checking and debugger stepping with code that verifies that your program does exactly what you intended it to do. ”
  8. ^ Muller, Matthias M. ; Padberg, Frank. About the Return on Investment of Test-Driven Development (PDF) 6. Universitat Karlsruhe, Germany. Retrieved on 2007-11-01. Year 2007 ( MMVII) was a Common year starting on Monday of the Gregorian calendar in the 21st century. Events 996 - Emperor Otto III issues a deed to Gottschalk Bishop of Freising which is the oldest known document using the name Ostarrîchi

See also

External links

Java Testing

Windows/. NET Testing

Testing in other languages


© 2009 citizendia.org; parts available under the terms of GNU Free Documentation License, from http://en.wikipedia.org