Labels

Friday, June 19, 2009

Unit Testing || Rules to Better Unit Tests

Introduction

 

There are multiple practices for creating the Unit Test Cases.

Here is the complete reference: http://www.ssw.com.au/ssw/Standards/Rules/RulesToBetterUnitTests.aspx

 

However below is a concise list from the mentioned reference.

 

1.      Introduction

 

This document describes the guidelines for developers to build the Automated Unit Test Cases.

 

2.      Automated Unit Test Guidelines Best Practices 

 

·         A unit test is piece of code that invokes a different method and then checks some assumptions about the logical behavior of that method or class under test.

 

Logical code means any piece of code that has some sort of logic in it, small as it may be. It’s logical code if the piece of code has one or more of the following:

An IF statement

A loop

Switch case

any other type of decision making code

 

Properties (getters/setters) are a good example of code that usually does not contain any logic, and so does not require testing. But watch out, once you want to add any check inside the property, you’ll want to make sure that logic is being tested for correctness.

 

·         While writing the unit test case we should consider the following important criteria.

 

·         It is automated and repeatable.

·         It is easy to implement.

·         Once it’s written, it stays on for the future.

·         Anyone can run it.

·         It runs at the push of a button.

·         It runs quickly.

 

 

 

·         People aim for 100% Unit Test Coverage but in the real world this is 100% impractical. Unit tests are created to validate and assert that public and protected methods of a class meet an expected outcome based on varying input. This includes both good and bad data being tested, to ensure the method behaves as expected and returns the correct result or traps any errors.

 

·         Generally, private methods should not have unit tests written for them as they are not exposed to other objects outside the original class. These private methods are likely to be refactored (eg. changed, renamed) over time and will require the unit tests to be updated and this becomes a maintenance nightmare. So how do private methods get tested? Private methods should be tested by the unit tests on the public and protected methods calling them and this will indirectly test the private method behaves as intended.

 

Eg. You would test correct input such as 12/3 = 4 plus bad input such as 12/4 <> 4 and that 12/0 does not crash the application, and instead a DivideByZero Exception is thrown and handled gracefully.
Eg. Methods returning a Boolean value need to have both true and false test cases.

 

·         Never allow a situation where a developer can check out code and the code does not compile – or the unit tests are not all green. This is called “breaking the build” so follow following process to avoid such scenarios

Good Process

1.      Check out

2.      Compile

3.      Run Unit Tests

4.      If OK then start developing

5.      Develop

6.      Compile

7.      Run Unit Tests

8.      Check In

9.      Get Latest

10.   Run Unit Tests to confirm everything is working

 

 

·         An integration test would exercise many units of code that work together to evaluate one or more results, while a unit test would usually exercise and test only a single unit in isolation. Also in service layer one method calls another method from same layer, should be handled with separate test method as isolated method.

 

·         When you encounter a bug in your application you should never let the same bug happen again. The best way to do this is to write a unit test for the bug.

 

·         Unit Tests became unusable because the people who wrote them had left the project and no one knew how to maintain the tests, or what they were testing. The names we gave our unit test methods were not clear enough. We had tests relying on other tests. We ended up throwing away most of the tests so you always try to follow naming convention for unit test, it is more useful to satisfy the above two criteria for Good Unit Test Once it’s written, it stays on for the future. Anyone edit and run it.

 

·          

Test Object

Recommended Style

Example

Project Name

UnitTests

UnitTests

Test Fixture Name

[Type]Tests

OrdersTests, CustomerTests, DeveloperTests

Test Case

[Function]Test

ConstructorTest, InsertDataTest, LoginTest

Set Up

SetUp

 

Tear Down

TearDown

 

 

 

·         Exceptions that do not give the user a prompt that an error has occurred. Things such as: Arithmetic, Rounding or Calculations should have unit tests written for them also having unit tests for exceptions further raises your code coverage.

 

·         You have unit test case to test your database configuration and reconcile form rather than Test failed due to Database connection not available.

 

·         Always try decouple the Unit test code from the resources (file handling, Database).  An added benefit is the reduced running time of the tests. The faster the tests are, the more often they are run.

 

·         In a team environment, you can be sure your Unit Test Case doesn't break anyone else's Unit Test Case. It Should be shared with everyone or communicated to everyone if its gets updated.

 

·         A Unit test case should be able to run completely by itself without any human input. Unit testing is about automation. It should determine by itself whether the function it is testing has passed or failed, without a human interpreting the results

 

 

·         Writing unit tests for the happy path is the easy part. The trickier part is how to test all those other scenarios in the use case, typically referred to as alternate paths. Alternate paths are actually quite easy to recognize in code. They are the If…Else statements and the Switch…Case statements. Each check in an If…Else statement or Switch…Case statement requires a corresponding unit test.The importance here is again code coverage. Having unit tests that hit the alternate paths of a use case will greatly increase your code coverage

 

·         To ensure quality unit tests are written and most test data should be created at the start of a unit test and deleted once the test is completed. This allows for each unit test to setup and tear down its own test data independent of other unit tests. 

 

·         More often applications are broken into several layers that include the UI, business logic, data access, service agents, etc. Each layer should have its own standalone set of unit tests so that the layer can be properly tested independent of any other layer. Meaning, layers should not depend on getting its test data from another layer. The unit tests for each layer must maintain their own sets of test data. There will be instances when a method is nothing more than a pass-through from one layer to another. In this situation the pass-through method should still have its own set of unit tests

 

 

·         Run Unit Tests for Each Layer by Them selves, this is important because it affects your code coverage metrics. Meaning, if you only ever run unit tests end-to-end with layers passing test data to other layers, it’s highly possible your code coverage statistics will be misleading (i.e. higher than it really is). To ensure your code coverage is at acceptable levels, you must run unit tests for each layer by themselves. This forces you to write unit tests for each layer, which in turn will require test data for each layer.

 

·         Run Unit Tests With All Layers Together, This is the end-to-end scenario mentioned above, which is important because it allows you to see how your unit tests perform when all layers are running together. If your code coverage is good when running each layer by itself, then it should also be good when running all unit tests from all layers together.

 

 

 

Hope this helps.

 

Thanks & Regards,

Arun Manglick || Senior Tech Lead

 

 

No comments:

Post a Comment