In my previous post we saw how we could test methods of class whose constructor does evil stuff. What if the static initializer of the class does evil stuff? How will we test such a class?
This is exactly what we are going to see in this post!
You might think why on earth would you want to do that? For a few very simple reasons like, legacy code, third party library, may be something else.
At times, we might have to use a third party library that does some weired stuff in static initializers. It might load a native library, may perform some IO operation, may open up a database connection etc.
When we are unit-testing a class that uses this third party class (whose static initializer does wired stuff), we simply don't want to deal with all this complication.
This is the reason why we might want to suppress the static initializer of a class.
Convinced about the "why"? Lets look at the "What" part.
Code under test:
Hmmm, looks like a familiar class?
We want to write a unit-test case for the AccountDAO class. In that we are interested in testing the findAccountById method. This method get a Hibernate session from HibernateUtils class and then invokes the get method on the session.
But look at how HibernateUtil class. It initializes the static SessionFactory instance. It does that in a static initializer! Man! this means every time the unit-test case for AccountDAO is executed the sessionFactory will be created. We don't want that to happen do we?
Also notice that, for testing purpose I have a System.out.println line in the static initializer of HibernateUtil. If we are successfully able to suppress the static initializer of HibernateUtil we should not be getting any output on the console.
So how do we write unit-test for AccountDAO class without initializing the SessionFactory. Lets look at the "How" part now.
How would we test it - How do they do it!
Turns out, as always, there is a very simple way to suppress the static initializers of any class using PowerMocks - Mocks on Steroids!
We simply have to use an annotation called @SuppressStaticInitializationFor. As the annotation reads it suppresses static initializer for a given class. But which classes static initializer do we want to suppress? How do we tell this to PowerMocks? Via passing the fully qualified class name to the @SuppressStaticInitializationFor annotation.
Here is the syntax
Please note that we are passing the fully qualified class name as string to the @SuppressStaticInitializationFor annotation. Unlike in the case of @PrepareForTest annotation where, we pass the class reference like this
Can you tell me why this difference in the syntax? Well, for those who have not guess it, here's the answer:
Because if we pass the class reference like HibernateUtil.class then, by the time that statement executes the class is already loaded and static initializer would have already been executed. We don't want that.
Sole purpose of using the @SuppressStaticInitializationFor annotation was to suppress the static initializer of HibernateUtil class. And this is the reason we don't pass the class reference but we pass the fully qualified class name as string.
After a lot of explanation lets look at the complete test code
Thats it! We have managed to suppress the static initializer of a class.
Writing unit-tests with PowerMocks (Mockito api) is fun!
BTW the statement "The static initializer of HibernateUtil invoked" is never printed on the console. You will have to take my word for this! What? You don't trust me? Then, try the example on your own :)
Showing posts with label untestable code. Show all posts
Showing posts with label untestable code. Show all posts
Monday, June 21, 2010
Tuesday, May 11, 2010
Testing the Untestable code using PowerMock (Mockito api)
Taking inspiration from this excellent post by Johan Haleby, today I am going to jump a few gears and show you the real power of PowerMocks. I will show you how can we write good unit-tests to test the untestable code!
We will continue the How-To series using PowerMocks (Mockito api) but today lets look at something more complicated.
You must be thinking, if the code is untestable then how can we write unit-tests? But, that my friend is the real power of PowerMocks, we can write unit-tests for testing untestable code as well!
So What are we testing today.
The code example is taken from one of the code samples of JMockit unit-testing framework (which by the way is another powerful unit-testing framework). At first glance the code might not look as complicated, but make a note of the following points and then think how will you ever write a unit-test for doBusinessOperationXyz method?
Wow! it seems like a really tough class to test. Lets move ahead and write some good unit-tests to test the above code!
How will we test it - How do they do it!:
You will be surprised to know that, we could write multiple unit-tests for the above code depending on what exactly we want to test! How awesome!
Test Requirement 1:
Lets say we want to test that, the ServiceB was invoked to compute total.
Test Code:
As usual we have to annotate the TestCase with @RunWith annotation (go here know more on why we have to do so).
We can verify that computeTotal method was invoked on ServiceB instance via a mocked ServiceB object. But if you think about this for a moment, how can we do that? Because ServiceA's doBusinessOperationXyz is actually instantiating ServiceB.
How can we suppress this behavior and inject our mocked ServiceB object? Simple! via byte-code manipulation of ServiceA class :)
No no, don't worry, we don't have to do byte-code manipulation on our own, PowerMocks does that for us. All we need to tell PowerMocks is for which classes we want to perform byte-code manipulation using the @PrepareForTest annotation (go here to know more about @PrepareForTest annotation).
Another point is we want to mock static methods in Database class as well. Hence we have to use @PrepareForTest annotation for Database class as well.
And finally, note that since we want to mock ServiceB class, which is a final class we have to use @PrepareForTest annotation for ServiceB class as well.
Enough fluff, show me the stuff!
The unit-test code looks like this
Thats all folks! We have successfully tested the Untestable code for our first requirement
Thats all folks! We have successfully tested the Untestable code for our first requirement
Test Requirement 2:
Lets say we want to test that, the Database was used to save EntityX.
Test Code:
Now that you have read the post so far, this one must look straightforward to you!
The test-case looks like
Thats it!
Test Requirement 3:
Database find was invoked to get the list of EntityY
Test Code:
The test-case looks a lot similar to the previous example
I promise its not much after this.
Test Requirement 4:
Should verify that EntityY list returned from Database.find was used to computeTotal
Test Code:
This is the final one.
Test Requirement 5:
Should verify that computed total was set on EntityX instance
Test code:
Done! Its pretty evident from the above examples that testing the Untestable code is pretty easy using PowerMocks (Mockito api)
Feedback, questions and comments are welcome as usual!
We will continue the How-To series using PowerMocks (Mockito api) but today lets look at something more complicated.
You must be thinking, if the code is untestable then how can we write unit-tests? But, that my friend is the real power of PowerMocks, we can write unit-tests for testing untestable code as well!
So What are we testing today.
Code to Test:
The code example is taken from one of the code samples of JMockit unit-testing framework (which by the way is another powerful unit-testing framework). At first glance the code might not look as complicated, but make a note of the following points and then think how will you ever write a unit-test for doBusinessOperationXyz method?
- The ServiceA class is final
- It invokes a static method on Database class called find which returns a list
- It then creates a new instance of ServiceB class and invokes computeTotal method, passing it items retrieved from Database.find call
- ServiceB class is final as well
- Invokes another static method on Database class called save, passing it the EntityX instance
Wow! it seems like a really tough class to test. Lets move ahead and write some good unit-tests to test the above code!
How will we test it - How do they do it!:
You will be surprised to know that, we could write multiple unit-tests for the above code depending on what exactly we want to test! How awesome!
Test Requirement 1:
Lets say we want to test that, the ServiceB was invoked to compute total.
Test Code:
As usual we have to annotate the TestCase with @RunWith annotation (go here know more on why we have to do so).
We can verify that computeTotal method was invoked on ServiceB instance via a mocked ServiceB object. But if you think about this for a moment, how can we do that? Because ServiceA's doBusinessOperationXyz is actually instantiating ServiceB.
How can we suppress this behavior and inject our mocked ServiceB object? Simple! via byte-code manipulation of ServiceA class :)
No no, don't worry, we don't have to do byte-code manipulation on our own, PowerMocks does that for us. All we need to tell PowerMocks is for which classes we want to perform byte-code manipulation using the @PrepareForTest annotation (go here to know more about @PrepareForTest annotation).
Another point is we want to mock static methods in Database class as well. Hence we have to use @PrepareForTest annotation for Database class as well.
And finally, note that since we want to mock ServiceB class, which is a final class we have to use @PrepareForTest annotation for ServiceB class as well.
Enough fluff, show me the stuff!
The unit-test code looks like this
Thats all folks! We have successfully tested the Untestable code for our first requirement
Thats all folks! We have successfully tested the Untestable code for our first requirement
Test Requirement 2:
Lets say we want to test that, the Database was used to save EntityX.
Test Code:
Now that you have read the post so far, this one must look straightforward to you!
The test-case looks like
Thats it!
Test Requirement 3:
Database find was invoked to get the list of EntityY
Test Code:
The test-case looks a lot similar to the previous example
I promise its not much after this.
Test Requirement 4:
Should verify that EntityY list returned from Database.find was used to computeTotal
Test Code:
This is the final one.
Test Requirement 5:
Should verify that computed total was set on EntityX instance
Test code:
Done! Its pretty evident from the above examples that testing the Untestable code is pretty easy using PowerMocks (Mockito api)
Feedback, questions and comments are welcome as usual!
Subscribe to:
Posts (Atom)