• 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:
  • Tim Cooke
  • Campbell Ritchie
  • paul wheaton
  • Ron McLeod
  • Devaka Cooray
Sheriffs:
  • Jeanne Boyarsky
  • Liutauras Vilda
  • Paul Clapham
Saloon Keepers:
  • Tim Holloway
  • Carey Brown
  • Piet Souris
Bartenders:

Code and design quality vs. testability

 
best scout
Posts: 1294
Scala IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello rangers,

one thing I'm still often wondering about when it comes to testing is how I should decide between better code and design practices vs. easier testability. In particular I'd like to hear your opinions regarding Java's "final" keyword.

Static analysis tools and lots of advices and best practices for good application design suggest that it's considered better design to make methods (or classes) final, if you don't explicitly want them to be overridden in subclasses.
I'm currently working on a project where inheritance is primarily used to combine big classes into giant classes via inheritance without thinking about the real purpose of inheritance. Therefore I can really see the value to use the final keyword to enforce for example the open closed principle or liskov's substitution principle and prevent others from accidentally overriding methods incorrectly and violating the said rules.

On the other hand from a testing perspective it's quite handy to have non-final methods and classes. It's always very convenient for me to be able to override a method for testing purposes which would not be possible with final classes or methods. Of course I know there are frameworks like JMockit which allow to circumvent almost any hurdle like final, private or static modifiers. Especially this testing framework is very powerful and easy to use, at least in my opinion. But still this feels more like a hack if you need a framework to manipulate the bytecode of a class to make it testable. This makes it very tempting to leave out final modifiers or loosen access modifiers to make your code easier testable without the need for special frameworks.

A third alternative I recently read about is to provide separate test-specific implementations for critical classes of your API which are solely intended to be used for testing. This idea combines the best of both worlds but obviously it comes at a price, i.e. you have to maintain additional classes just to make your code testable.

Maybe this discussion wouldn't be necessary if everyone on the team works very, very disciplined but even this doesn't completely prevent mistakes which could be hard to fix later. So I personally would tend not to make compromises and reduce the code quality just for the sake of easier testability. Of course it may depend on other factors like the application, the team etc. but I'd still love to hear your opinions on this topic. What is your practical experience with this?

Thanks for your answers!

Marco
 
author & internet detective
Posts: 42135
937
Eclipse IDE VI Editor Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Marco,
I think this is an interesting topic.

I very rarely make my methods/classes final because I don't know in advance that they shouldn't/won't be extended. So I've never faced this particular design issue.

On the package private issue that comes up periodically, I have no problem making methods package private to be testable. The unit tests are a legitimate client of the code and deserve to have their needs met too
 
Marco Ehrentreich
best scout
Posts: 1294
Scala IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Jeanne,

I'm glad to hear some comments on this topic.

I very rarely make my methods/classes final because I don't know in advance that they shouldn't/won't be extended. So I've never faced this particular design issue.


Of course I understand that the "final" keyword is not necessarily a big problem. Maybe you've been lucky enough that you've never had a need for it. I think of the "final" keyword in the sense of defensive programming. Just like checking for null values vs. not using null as regular return value or parameter.

In my opinion it makes a big difference if you're working with a highly disciplined team on a project which doesn't require a very long maintenance period. Or if you are working on a project which is permanently extended and changed over several years with an ever changing team. In the latter case I see the value of "final" in that you can force other people to stop and think about it a moment if they want to override a method or inherit from a base class just to get something done without taking care of the consequences for any design issues.

On the package private issue that comes up periodically, I have no problem making methods package private to be testable. The unit tests are a legitimate client of the code and deserve to have their needs met too


I think it's the same conflict here. In general I'd say there's nothing wrong with making something package private to make it easier testable. On the other hand there will be situations where you would like to enforce strict access rules. I mean technically you give other team mates the chance to override something accidentally if they don't work as careful as they should or don't care about that the package private modifier is only there for testing purposes.

That said I'm aware of the fact that this is always a trade-off. I'm pretty sure some people would complain if you allow to modify the production code to make it easier testable while others would complain that this makes the code unnecessarily difficult to test. That's the whole reason I wanted to hear some opinions on this.

Marco
 
Greenhorn
Posts: 6
Eclipse IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello Marco,
I thought of putting some comments here as I have been thinking a bit on this lately. I would rather think of future maintainance of a project. And this would probably say that it's better to have final methods in your classes, since the project may land in the hands of a new coder rather an inexperienced person. In this case and at such experience the coder would try changing the overridden method (which typically should not have been overridden) unknowingly and create a huge impact on the overall flow. Such things are little bit difficult to track and waste unnecessary time.
That was one point for the final methods, the other point would be knowing whether in future you are going to extend the class method or not. This depends entirely on the designer that how he/she designs the project and while in the process of designing he/she should know what methods should be overridden and what methods should not. I don't remember any scenario where one would change the design to overridde a method which is declared as final.
 
Marco Ehrentreich
best scout
Posts: 1294
Scala IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Abhijeet,

thanks for your comment!

That's exactly my point of view, too. As I already wrote I can understand that it's not necessary for all applications and/or teams to care about making methods "final". But from my experience there's no other way to stop others from blindly building inheritance trees without thinking about the consequences. In particular this is true if you can't control who will do the maintenance work later, as you said. And more often than not inheritance is used incorrectly anyway. Maybe final methods may help more inexperienced developers to think about if overriding is practice of choice to achieve some goal.

Anyway, this only helps to keep the production code clean but it doesn't solve the testability issues you implicitly get with final methods. What do you do to make such code testable (i.e. if you can't simply override methods to create a simple fake or stub object etc.)? That means, if you do care about testability at all... Do you use mock frameworks which can handle final methods? Or do you provide separate test classes for the critical parts of an API?

Marco
 
Abhijeet Dalal
Greenhorn
Posts: 6
Eclipse IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
My understanding of a final method is that a method is made final when we know what exactly is expected out of it and the behaviour is common to all subclasses. And one should be very careful in making a method final, thats the part of the designer who would design the classes. It's better to be very clear to why the method should be final.

Now the part for unit testing a final method. Suppose we have a final method myFinalMethod(parameters) in the class MyClass. This method has a very strict behaviour and returns a object of say a String. This string is a known string to the business/designer/developers i.e. a particular pattern. You use Junit for unit testing, which has a method called assertEquals(). This method has 2 parameters one is the expected output and the other is the output from the method.

In our example the code snippet would look like:



This is just a small example and we can think of different ways to handle final methods. I am not sure whether you are looking for something like this and I don't see any need to override a final method if we have clear understanding about why we need a final method.
 
Marco Ehrentreich
best scout
Posts: 1294
Scala IntelliJ IDE Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi Abhijeet,

thanks for your explanation. Of course I'm aware that you shouldn't modify the intended design of a class by either adding or removing the "final" modifier. If the future evolution of a class is unclear, I'd still prefer to make it final though. This makes you or other think about it some time later before overriding it accidentally and breaking the contract of the method. And if it's really necessary to override a method later it's not a big problem to remove the final keyword (if it's your own code of course) which still should be more or less an exceptional design change.

To your answer regarding testability of final methods: I think I should have explained it clearer. Of course I'm familiar how to test an ordinary method with JUnit or TestNG where final methods shouldn't make a difference. What I really wanted to discuss was how you solve the problem when you don't want or can't use the real method in a test but instead have to override (i.e. create a fake or stub of a dependent-on-component) this method, for example to prevent it to talk to a real database or something like this. In that case overridable methods are really handy because it's often enough to create an anonymous class inline in a test method and override the specific method. With final methods this is of course not possible and you have to use a framework which is capable of mocking final methods or you have to provide special test doubles for production classes or maybe something else... I hope this explanation makes it clearer, what I wanted to know.

Marco
 
reply
    Bookmark Topic Watch Topic
  • New Topic