By Subham Aggarwal | 5/24/2017 | General |Beginners

Unit Testing

Unit Testing

Unit Testing is a component of Test Driven Development (TDD) in which test cases are written to deliberately fail, followed by development of the product with continued testing until all test cases pass.

 

This methodology involves writing test cases which test only a single unit of code at a time, which can be a method, a short program or a complete component. More than that, unit tests tend to become integrated tests in which two or more units are joined together and tested.

Advantages of Unit Testing

  • Reduce defects in the newly developed features or reduced bugs when changing the existing functionality.
  • Reduced cost of testing as defects are captured in a very early phase.
  • Improves designs and allows better refactoring of code.
  • When unit test cases are written, those test cases can provide the quality of the build as well.
  • As unit test cases are very short, they are easy to write.
  • When a unit test case fails, it is easy to identify exactly which unit has failed the test.

 

Now let us see how unit testing works.

unit testing flow chart

Techniques for Unit Testing

There are three techniques to execute unit test cases:

  • Black box testing tests only the functionality of the software. Internal structure of the software is not tested in this type of testing and this method can be applied virtually to every level of software testing be it unit, integration, system, or acceptance testing.
  • White box testing is a testing technique which examines the program structure and derives test data from program logic. This technique forces a developer to reason carefully about the implementation of his logic. This technique also reveals errors in hidden code.
  • Lastly Grey box testing is a technique which is used to execute test and assessment methods.

Performing Unit testing

  • To start, it is always useful to find a tool/framework for your language.
  • Do not create test cases for everything. Instead, focus on the tests that impact the behavior of the system.
  • It is important to isolate the development environment from the test environment before executing any unit cases.
  • Use test data that is as close to that of production as possible.
  • Write test cases that are independent of each other. For example, if a class depends on a database, do not write a case that interacts with the database to test the class. Instead, create an abstract interface around that database connection and implement that interface with a mock object.
  • Aim at covering all paths through the unit. Pay particular attention to loop conditions.
  • Make sure you are using a version control system to keep track of your test scripts.
  • In addition to writing cases to verify the behavior, write cases to ensure performance of the code.
  • Perform unit tests continuously and frequently as you add new features to the project.

Womp's 5 Laws of Writing Tests

  1. Use long, descriptive test method names.

 

Map_DefaultConstructorShouldCreateEmptyGisMap()

 

ShouldAlwaysDelegateXMLCorrectlyToTheCustomHandlers()

 

Dog_Object_Should_Eat_Homework_Object_When_Hungry()

 

  1. Write your tests in an Arrange/Act/Assert style.

 

While this organizational strategy has been around for a while and has been called many things, the recent introduction of the "AAA" acronym has been a great way to get this across. Making all your tests consistent with AAA style makes them easy to read and maintain.

 

  1. Always provide a failure message with your Asserts.

 

Assert.That(x == 2 && y == 2, "An incorrect number of begin/end element processing events was raised by the XElementSerializer");

 

  • A simple yet rewarding practice that makes it obvious what has failed in your runner application. If you don't provide a message, you'll usually get something like "Expected true, was false" in your failure output, which makes you have to actually go read the test to find out what's wrong.

 

  1. Comment the reason for the test—what’s the business assumption?

 

/// A layer cannot be constructed with a null dbLayer, as every function

/// in the Layer class assumes that a valid dbLayer is present. [Test]

public void ShouldNotAllowConstructionWithANullDbLayer() { }

 

  • This may seem obvious, but this practice will protect the integrity of your tests from people who don't understand the reason behind the test in the first place. I've seen many tests get removed or modified that were perfectly fine, simply because the person didn't understand the assumptions that the test was verifying.
  • If the test is trivial or the method name is sufficiently descriptive, it can be permissible to leave the comment off.

 

  1. Every test must always revert the state of any resource it touches
  • Use mocks where possible to avoid dealing with real resources.
  • Cleanup must be done at the test level. Tests must not have any reliance on order of execution.

When is a Unit test case called Good?

A Good Unit test should be a trip. It should have all of features mentioned below collectively.

  • Automatic: Invoking of tests as well as checking results for PASS/FAIL should be automatic.
  • Thorough: Coverage; Although bugs tend to cluster around certain regions in the code, ensure that you test all key paths and scenarios. Use tools if you must to know untested regions
  • Repeatable: Tests should produce the same results each time, every time. Tests should not rely on uncontrollable parameters.
  • Independent: This is very important.
    • Tests should test only one thing at a time. Multiple assertions are okay as long as they are all testing one feature/behavior. When a test fails, it should pinpoint the location of the problem.
    • Tests should not rely on each other and should be Isolated. No assumptions about order of test execution. Ensure 'clean slate' before each test by using setup/teardown appropriately
  • Professional: In the long run you'll have as much test code as production (if not more), therefore follow the same standard of good-design for your test code. Well factored methods-classes with intention-revealing names, no duplication, tests with good names, etc.
  • Good tests should also run fast. Any test that takes over half a second to run, needs to be worked upon. The longer the test suite takes for a run, the less frequently it will be run. The more changes the dev will try to sneak between runs, if anything breaks. It will take longer to figure out which change was the culprit.

Conclusion

While it is possible to introduce a bug in both the code and test it rarely happens in actual practice. It does occasionally happen that the test is wrong, but the code is right. This is revealed when the problem is investigated and fixed. Creating tests independent of code, hopefully before code, sets up checks and balances and greatly improves the chances of getting it right the first time.

 

Unit Tests provide a safety net of regression tests and validation tests so that you can refactor and integrate effectively. As they say in the circus, “never work without a net!” Creating the unit test before the code helps even further by solidifying the requirements, improving developer focus, and avoid creeping elegance.

By Subham Aggarwal | 5/24/2017 | General

{{CommentsModel.TotalCount}} Comments

Your Comment

{{CommentsModel.Message}}

Recent Stories

Top DiscoverSDK Experts

User photo
3355
Ashton Torrence
Web and Windows developer
GUI | Web and 11 more
View Profile
User photo
3220
Mendy Bennett
Experienced with Ad network & Ad servers.
Mobile | Ad Networks and 1 more
View Profile
User photo
3060
Karen Fitzgerald
7 years in Cross-Platform development.
Mobile | Cross Platform Frameworks
View Profile
Show All
X

Compare Products

Select up to three two products to compare by clicking on the compare icon () of each product.

{{compareToolModel.Error}}

Now comparing:

{{product.ProductName | createSubstring:25}} X
Compare Now