It's not a secret anymore!*
The moose likes Testing and the fly likes How to Spy a Method Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Engineering » Testing
Bookmark "How to Spy a Method" Watch "How to Spy a Method" New topic
Author

How to Spy a Method

Anderson Council
Greenhorn

Joined: Nov 15, 2011
Posts: 7
Hey all, need a little help here.

I've been writing unit tests now for about a month or so, retroactively. That is, we are trying to get to a test-driven development paradigm, but for now, we need to cover our existing code base. We are using JUnit 3 and JMock 2.5.1.

The issue is as such:

I have a method of a class that I wish to test. It does certain things depending on parameter state, like any good ole method. However, at the end of this method's execution, it daisy-chains to another method. This second method is not one that we wish to test, especially as its code just creates an HTTP connection to a URL and posts a message there. I want to write my tests and expectations in such a way that I can expect the method invocation, but not actually execute the code in that method.

Now, having done quite a bit of reading and Googling about this, I have not been able to find the answer I need, but what I want to do is apparently called 'method spying'. Any idea how to do this? This is a scenario where I must stay within the constraints of the existing environment (no new jars, no new frameworks - just JUnit and JMock).

Example:

Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2341
    
  28

IMO, you should move the code that posts the HTTP request into it's own service. In your unit test you can mock the service.
Anderson Council
Greenhorn

Joined: Nov 15, 2011
Posts: 7
Jayesh A Lalwani wrote:IMO, you should move the code that posts the HTTP request into it's own service. In your unit test you can mock the service.


That's actually a good idea (plus one for you)...sometimes, I get too bogged down in the problem that I miss the easy solutions. And further than just being a good idea, it makes my code testable, increases encapsulation, and making your recommended change isn't just 'writing code so that I can test'. Kudos.

However, that being said, I would still like any input apart from moving the method to a class and then mocking it. Although adequate and appropriate for this scenario, there are others coming up for me where this will not be a viable solution. That is, there will be instances in which I will want to expect a method invocation and not actually execute the code in said method.

From the research I've done on this, the name for what I'm describing is called 'spying' on a method. Doing what research I could on JMock and JUnit, it seems that this may be possible using some bevy of Invocation classes from JMock - I haven't been able to figure out how, though. It seems as though I should be able to basically write a dummy, or stub, method with the same method signature as the one being tested, and then somehow divert the method invocation to the stubbed method. Hope this helps anyone trying to help me.
Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2341
    
  28

Well you can always extend your class and override methodTwo and then test the extended class. I am not very familiar with JMock. I am not sure if it can create a proxy for you. Or if JMock doesn;t, you'll have to use CGLib which may or may not be available to you.

However, I wouldn't be comfortable with the approach of not testing some things in your class in the unit test. Your unit test should be testing that the class satisfies the public contract. If the public contract says that "It will do foo and then call a web service called bar", your unit test should test that the class is "doing foo and calling the web service bar". It shouldn't just test that the class does foo. You are breaking the spirit of unit testing the class. If there is a problem in methodTwo, your class will fail in production, even if your unit test passes.

Now, if your public contract was that the "class does foo and then fires a notification to a listener", your unit test can then implement a mock listener to the class, call it and then make sure that it did foo and also called your mock listener. You would then have an implementation of a listener that fires the HTTP request, and you will have a separate unit test for that listener.
Anderson Council
Greenhorn

Joined: Nov 15, 2011
Posts: 7
Well, maybe you can help my understanding here a tad bit. Here's the code that I moved into its own class. This is what's called from the previously mentioned method that I wish not to test.

Here's the way I see it, though: this particular class/method should basically be black box from my testing point of view, at least when I'm testing the calling method. My test does assert that this method is invoked, so long as business logic requirements are met. So, my test does make sure the contract is being fulfilled from that point of view. From a "unit" testing point of view, testing the functionality of this method/class from another method would be inappropriate, unless that was the only way it could be invoked.

That being said, you're saying that regardless of when/where I test this code, it should still be subjected to some series of unit tests. My question is, how? Why? To me, there's nothing in this that can really be tested, apart from maybe the properties being read. This method's job is to create a connection to a URL, the value of which could change at any time, breaking a unit test or its functionality in production. How can I test that. Also, my understanding is that my unit tests shouldn't be testing against externalities, which is what a URL connection would be.

Not trying to argue, just trying to understand; feel free to call me out if I said or understood something incorrectly. Your insights are appreciated, by the way, thanks for your input on this topic.



Jayesh A Lalwani
Bartender

Joined: Jan 17, 2008
Posts: 2341
    
  28

I would unit test this method by having it connect to a mock URL

As far as answering the question:- Should a trivial method be tested? In an ideal world, yes, Ideally, your unit tests should cover 100% of your code. In a practical world, you may elect to not unit test trivial methods, but you are taking a risk there, or IOW, you are incurring some technical debt. It's really a judgement call based on time constraints and the tradeoff between effort and benefit.
Anderson Council
Greenhorn

Joined: Nov 15, 2011
Posts: 7
Your points are well-taken. Thank you for your input and assistance.

For others interested in more conversation on this, it's worth visiting the topic at http://old.nabble.com/How-to-Spy-a-Method-to32850127.html as well.
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: How to Spy a Method