• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • paul wheaton
  • Paul Clapham
  • Ron McLeod
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Roland Mueller
  • Piet Souris
Bartenders:

Unit testing static methods

 
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

post Tools for testing static methods talks about the subject of unit testing static methods.

In short, one wants to unit test ClassA, but ClassA uses some ClassB's static methods.

There, it was advice to wrap those static calls using interfaces and so on..

That is a good solution and sounds like good OO and the code looks pretty much like IoC. But what if you cannot do it. What if you have to call those methods statically (just because the client wants that way, and that's that!)?

Trying to figure out how could I unit test a ClassA, I started to think that I could try to change the system class loader. Such that when a request for ClassA's bytecodes was made, I could return the real ClassA, and when a request for ClassB was made, I could return a faked ClassB (compiled at runtime, for instance).

Does anyone has a clue if it is possible? I've seen that the java command has an "-Xbootclasspath" flag, but I think I doesn't help much.

Or someone has a better idea (but please, don't tell me to say dirty words to the client)?

Thanks.
Itapaj�.

[ EJFH: Fixed link ]
[ November 14, 2005: Message edited by: Ernest Friedman-Hill ]
 
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Itapaj� Takeguma:
What if you have to call those methods statically (just because the client wants that way, and that's that!)?



I'm not sure I understand your situation. Can you please elaborate on why you can't wrap the static methods?
 
author and iconoclast
Posts: 24207
46
Mac OS X Eclipse IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ilja Preuss:
Can you please elaborate on why you can't wrap the static methods?



He can't mock them directly because they're static, but for some reason, the client insists that they be static and be called statically.

So you can't change class A. Can you change class B, the one with the static methods? In that case, you could make the static methods themselves delegate to an object, and you could mock that object during tests!
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Ernest Friedman-Hill:
He can't mock them directly because they're static, but for some reason, the client insists that they be static and be called statically.



How can a *class* "insist" on making a static method call? Does that simply mean you are not allowed to change it? Then what are you unit testing it for?
 
Itapaj� Takeguma
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Well (Preuss)... I really can't change signature and I can't change implementation. If I asked the client (the one who is paying for the system (the sponsor), not client in the sense of the one who is using the class (the caller)), he will just say: "hey, I architectured this way. If you don't like it, I'll find one who will" (but in portuguese).

Any away, I understood the solution advocated by Friedman-Hill [thanks for your posting], but unfortunately I should be able to test the class without changing it in any way. I can do whatever I want with the unit tests, but nothing at all with the classes.

That's why I started to think about deceiving class A at a much lower level: loding a faked class... but I don't know if it is possible, given that class B is in the class path!

thanks for all of you,
Itapaj�.
 
author
Posts: 11962
5
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Itapaj� Takeguma:
That's why I started to think about deceiving class A at a much lower level: loding a faked class... but I don't know if it is possible, given that class B is in the class path!


I suppose it would be technically possible. For example, by simply placing your fake class into the classpath before the real class. However, that would pose some interesting issues with regards to your development environment--you'd need to copy that class to and from the classpath based on whether you want to run with or without the real class.

Another option might be to implement a custom ClassLoader that would, for a given class, load the class from some known place rather than asking the parent classloader first like it should. If you end up trying this and it works out (or almost works out), I'd be interested to see the solution...
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Originally posted by Itapaj� Takeguma:
I really can't change signature and I can't change implementation. If I asked the client (the one who is paying for the system (the sponsor), not client in the sense of the one who is using the class (the caller)), he will just say: "hey, I architectured this way. If you don't like it, I'll find one who will" (but in portuguese).



What if you didn't tell him you don't like it, but simply provided him two estimates for the costs of implementing the tests: one with the "architectural" change, and the other without? (It's important here that he doesn't get the impression that you prefer one approach over the other.)
 
Itapaj� Takeguma
Ranch Hand
Posts: 41
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

Well Preuss, that is a very strong argument... I will try to expose it to the client! Thanks a lot.

But because I could not spoke to him today, I continued my way across the ClassLoaders and as Koskela asked me to expose my (awkward) work around, I dispose here a piece of the solution (it is still messy and deserves a lot of refactoring, but only if the client agrees to pay the price).

Part of the solution came from a pdf I found at google: Understanding the Java ClassLoader. The important idea taken from this document is that one can "set" a custom class loader. In my solution, I do:

java my_package.MockApplicationLoader my_package.MockClassLoader junit.textui.TestRunner MyTest

The MockApplicationLoader instatiates the MockClassLoader. It works like a bootstrap class, or the like.
The MockClassLoader loads the junit.textui.TestRunner.
And the TestRunner finally instatiates the MyTest.

MockApplicationLoader and MockClassLoader are loaded by the system class loader, while TestRunner and MyTest are loaded by MockClassLoader.

It seems to work and I could run some preliminary tests over JUnit's textui. When I run the JUnit's swingui I had some problems, I think it is possible that JUnit is overriding my class loader in some way.

It is remaning the part when I compile the mocked classes at runtime, but it isn't a big deal, I think.

Anyway, now I really agree with Preuss. It is too much work. Anyway, I think this "framework" might be valuable, because the client may have some static calls like these with no unit tests.

Thanks all,
Sory for the long text, but it was the shorter I could be,
Itapaj� Takeguma.
 
Ilja Preuss
author
Posts: 14112
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Nice to hear that you are coming closer to a solution - whatever it will turn out to be...

Originally posted by Itapaj� Takeguma:
When I run the JUnit's swingui I had some problems, I think it is possible that JUnit is overriding my class loader in some way.



Yes, the Swing UI uses its own classloader to be able to reload changed classfiles on a rerun. I think that can be disabled, though - there should be something in the JUnit FAQ about this, if I remember correctly.
 
With a little knowledge, a cast iron skillet is non-stick and lasts a lifetime.
reply
    Bookmark Topic Watch Topic
  • New Topic