Sunday, December 02, 2007

The Easiest and the Hardest Methods to write unit test for

I was wondering to find out the easiest methods to write unit tests for. I came up with a few results as the following ones...

a. A method that takes no parameter, perform calculations on only local data and always returns a constant value is the easiest to test. But the question is, is this at all important to have such methods?

b. A method that takes some parameters, and limits its operations only on the supplied parameters and local variables and returns some value or throws exception is also very easy to write a test for.

Now, we want all our methods to be easily unit testable. But the reality is, we cannot always have the most convenient forms for unit testing with real life methods.

And things start to go wrong as we have deviations from the ideal. Some of the most commonly found deviations are -
1. void methods that optionally throws exception
2. void methods without exceptions
3. Methods without parameters.
4. Methods having multilevel nesting and complex flow.
5. Methods that depends on other methods or classes or modules.
6. Methods having dependency on static methods.
7. Methods with a risk of runtime exception.

I will be posting rescue scenarios with appropriate reasoning to get around to the discomforts of the above listed deviations from ideal unit testing perspectives.

Stay tuned to get more on this...:-)

Unit Testing void Methods - Part 2

Dissection of void Methods with parameters

Methods with void return types incur complexities in writing unit tests. So, we need to characterize the void methods to make sure we have guards against the odds for testability.
For example, the following is a void method with parameters

public void DoSomething(SomeType obj, SomeOtherType objOther)

{

//1.modifies some member variables

this.someMemberVariable = 10;

//2.Calls methods of the same class or other classes

someOtherClass.SomeOtherMethod(someArg);

//3.Sometimes throws exception


//4.Modifies call by reference type argument objects

obj.SomeProperty = objOther.GetResultOfSomeAction();

objOther.DeleteSomething();

}


Unit test examples for all the scenarios other than 4 are discussed in Part -1 of this article.

d. In such cases, the unit test assertions are made to test against the expected value of the supplied argument objects after the method is invoked.




Unit Testing void Methods - Part 1

Dissection of void Methods without parameters

Methods with void return types incur complexities in writing unit tests. So, we need to characterize the void methods to make sure we have guards against the odds for testability.

A typical void method without any parameter looks like the following

public void DoSomething()
{

//1.modifies some member variables
this.someMemberVariable = 10;

//2.Calls methods of the same class or other classes
someClass.SomeOtherMethod(someArg);

//3.Sometimes throws exception
}


So, we need to make sure we can test all the activities performed by such a method. The following are the illustrative examples showing the unit test solutions case by case

a. To test a method that modifies a member variable we need to write assertions on the member variables accessors. If this is a private member without a getter method then we will overlook it for the same reason as we discard the testing of private members

Note: Examples coming up shortly.

b. If this method calls a method from this class, we need to make sure that the called method is tested. If the called method belongs to anther class then, we can use dependency injection to use a mock for this method or make sure this method is testable.

Note: Examples coming up shortly.

c. If a method throws exception on some certain conditions, we can test for that exception with the appropriate conditions.

Note: Examples coming up shortly.

Saturday, December 01, 2007

Object Graphs and Dependency Injection

An application is supposed to have a graph of objects as a result of the following-

1. Objects are designed to be interacting with each other following two rules of thumb "Highest Cohesion" and "Lowest coupling". So, a class instead of taking all the responsibilities only takes care of some high cohesive ones and depends on other partner classes for the rest of the services. This dependency creates a graph like structure with objects as the nodes and dependencies as the edges.

2. We expect our classes to "take only single responsibility" and "encapsulate anything that varies" to make sure we have good compact manageable classes. But this at the same time means a lot of new dependencies resulting in a complex graph of objects. The more one class is used and reused we have even more complex graph..


This dependency graph stands in a cut-point of the two conflicting interests. A class with less dependency makes it easy to "test", but a class with less dependency "looses re-usability". Because, once a class has a lot of dependencies, its hard to isolate an independent part of the class and test. On the other hand, if a class has only a few dependencies, its likely that the class is doing a lot of stuffs itself and so, has many reasons to change.

Now to break the trade-off, I consider the key points again. If a class is high cohesive, it must depend on other classes for some non-cohesive services. This will also break down the classes into smaller classes which are more likely to be reusable than the longer ones. So, I have the feeling that dependencies are not that bad.

Now, the problem boils down to testing a class with all the dependencies on other classes. Well, we cannot actually delete the dependencies, still, we can inject them!

I hope to follow up on my understanding on dependency injection soon in my future posts.

Wednesday, November 28, 2007

Prerequisites for IID

Up to now, I have figured out that teams trying to behave agile sometimes fall into the cave of pretending to be agile (e.g. stand up meetings and less than just enough planning and short iterations so on!). Often, when this pretending takes places for days, it creates a illusion on the minds of the people that they might be doing the "right thing". And all on a sudden, someone discovers things are breaking and there is no way out of this disaster!

So, I suggest for teams who are trying to get agile to meet the following prerequisites first-

1. Team members must have a certain level of all-round skills.

So, when we do not preserve seats for requirements gathering, planning and designing and still want a good architected software, we need to make sure we are not asking beyond the capacity of one team member. From my experiences I have found that, even a very good communicating team with enough of discussions and reviews cannot control the quality and integrity of the product when some of the fellows don't meet the all-round skill requirements.

So, an agile team is expected to meet all-round individual skills like
a. Database design concept.
b. Object Oriented design concept (must know about design patterns (e.g. from GoF) and design principles)
c. Standard Coding expertise.
d. Testing sense and writing effective test codes.
e. Understanding the business domain clearly and concisely.
f. Quickly respond to change requests and define effective way to meet system owner's demands.

2. An "agile" skilled team must practice the following

a. Effective Design and design reviews.
b. Good coding at the very first time (if possible).
c. Must write test/guard codes for automated testing.
d. Continuous and periodically re-factorization of the code base and architecture.
d. Some sort of mentoring to make sure things are in rhythm.

3. An "agile" skilled team must use appropriate tools for the "best practices"

a. Use smart collaboration tool to make sure all the stakeholders are on the same ground.
b. Use effective test suits.
c. Version management system.
d. Automated build system and continuous integrations.
e. Project management and time tracking software.

I will try to get more subjective on each of the items mentioned above in my upcoming posts.

Two Aspects of Agile Software Development Process

I have been in practice with the famous agile software development process called "Scrum" for more than a year. I have had the opportunity to see a SCRUM team developing from scratch in a completely start-up environment.

I will point to the two aspects as,
1. Management aspects.
2. Technical aspects.

1. Management aspects
I encapsulate the things like working on a story by story basis, standing up for daily status update meeting, producing deliveries in short iterations and without much of prior planning into this group. I believe this aspect heavily depends on the way the second aspect is handled.

2. Technical aspects
Technical aspects encapsulate the practice of Test Driven Development, continuous and periodic Refactoring and other hard core technical things like this. Despite the truth that, this aspect is not the much anticipated by the client, being "Agile" there is no alternative to achieve what is anticipated, "Business value", without this.

Developing Software falls into the category of craftsmanship. So, its hard to define the line and expect the players to stop on a referee's whistle. With agility, developers are free to add their creative inputs to the software design and code base. So, without attention to the technical aspects may lead to a process of "Iterative Incrementation Destruction" instead of "Iterative Incremental Develeopment".

In subsequent posts I will try to come up with actual examples in favor of first making the "techi" things right.

Visit www.scrumalliance.org for Scrum related knowledge.