Unit
testing is not a new concept. The basic idea is to create a program which will
make certain assumptions for a specific piece of code in our application and determine,
based on those assumptions, the code produces an expected result or not.
Defining a Unit Test
The
program which will perform test is called unit test.
An excellent definition of a unit test is:
Unit test is an automated piece of code which invokes method
or class being tested and then checks some assumptions about logical behavior
of that method or class. Unit test is almost always written using a unit-testing
framework. It can be written easily and runs quickly. It is fully automated,
trustworthy, readable and maintainable.
A
key concept in above definition is that each unit test must test one and only
one, behavior of the functionality being tested. For example, a method which
returns an object based on the id. The method can behave in either of two ways - If it finds
the object with the specified id then it should return the object. If it does not find the
object then it should return null. As the method has two behaviors, we would write two unit tests:
first to test the case where it finds the object and second to test when it
returns null.
It can lead for writing many unit tests for a single piece of code. It is okay
to have many unit tests, in fact, it is expected. Unit tests are executed
automatically and are very fast. So, it does not matter how many test cases we
have.
Also,
we should not delete unit test just because it succeeds. We should delete a
unit test only if we have removed from the application the corresponding
functionality being tested. It will ensure that we can run the test each time we
add new functionality or make any change in the application by ensuring nothing
has been broken by the addition or change.
With
Microsoft Test Framework, we can create unit tests as methods which are
decorated with the [TestMethod] attribute. The methods must be in a class which is decorated
with the [TestClass] attribute.
Structure of Unit Tests
One
of the most common patterns which should be followed when writing unit tests is
the AAA pattern, in which we write our unit test in three parts:
• Arrange: Set up the unit test. For example, we initialize variables
and objects so that they are ready to pass in code to be tested.
• Act:
Invokes the code we want to test. It means invoking a particular method which
we are trying to test.
• Assert: Analyzes result produced in the Act part. We might verify the
return value and any output parameters are what we expected.
Isolation
Another
important aspect of unit testing is that it should properly locate the source
of problem when it arises. By using unit testing, although we are testing only
small pieces of code, we should do the tests in an isolated environment. It is very
important to isolate our code from external resources out of our control (databases,
web services and file system etc.) as
• The resources might fail for unpredictable reasons.
• The data yielded by such external resources might be
unpredictable and non-repeatable (which really ruins the unit tests).
• The resources might not actually be available yet in our
development project.
Additional
benefit of testing in isolation is that we can test our code even if the
external resources are not ready to interact with it yet. Suppose we are
working as a team and our piece of code has a dependency on some piece of code
from a colleague but that colleague has not completed the piece of code yet. Or
suppose our code has a dependency on a completely external component (from a
third party or trading partner).
In
either case, by isolating our code, we do not need to worry about those
dependencies. We can move forward with our development and be ready to go when
the rest of team is ready.
Naming Unit Tests
An
ignored aspect of creating a good unit test is its name. Nothing prevents us
from naming our unit test something as generic as Test1(), it will
hardly give us any useful information. A common practice is to name our unit
test in a manner which gives developers as much information as possible when the
test gets fail. A good pattern of naming unit tests is to concatenate the name
of method being tested, the key assumptions and expected result. For example, UploadFile_ValidFileSpecificied_SizeOnServerOverZeroKb().
Properly
naming the test classes is also best practice. We should use same name as the
class to be tested and suffix Test. For example, HomeControllerTest - which raises an interesting MVC-related point: we can perform
unit tests on controller classes.
No comments:
Post a Comment