1

I usually set each attribute of a class as final (only for attributes that will be initialized within the constructor). The point is that I am now implementing a Mockup of an object for testing purpose. This Mockup extends the class that it is mocking up and this class has some final attributes. Therefore I'm forced to call the super() constructor within the constructor of the Mockup object. This breaks however the utility of the Mockup because I don't want it to initialize all of the attributes in the way the normal class does it. I'd rather call the Mockup constructor without calling to super() and doing whatever I want.

My question is: Is it a good practice to define attributes as final as long as they will force you to call the class constructor in the Mockup?

EDIT: I add some code. The problem in this case is that I'm using a singleton, I know that this is not a good idea when testing but in this case I cannot change it. So my intention is not to call this method in the Mockup.

public class ReportsDataManager {

private final Map<String, List<String>> translations;

public ReportsDataManager() {
this.translations = GenericUtils.getTranslation();
}

}

iberbeu
  • 15,295
  • 5
  • 27
  • 48
  • Can you post some code of the SUT and the intended test ? What is the sequence of public calls/messages (when posted to the class under test) that will result in the state required for the test? You shouldn't have to externally manipulate the private variables of the SUT. – Gishu Feb 27 '13 at 10:59
  • "but in this case I cannot change it." Change it! ;) http://stackoverflow.com/questions/2925459/refactoring-singleton-overuse – flup Feb 27 '13 at 12:04
  • What does the class under test look like? How does it use the ReportsDataManager? – flup Feb 27 '13 at 12:18
  • You're right flup, I should change that, but even if I remove the Singletone I could still have the problem. Just guess that this.translations is initialized in a way I don't like for the mock... – iberbeu Feb 27 '13 at 14:31

4 Answers4

3

Declaring attributes final is a very good practice when you can do it. It confers immutability - guaranteed thread safety. Breaking it to mock is a bad idea. Your design should serve the user's needs, not your testing convenience.

duffymo
  • 305,152
  • 44
  • 369
  • 561
  • I agree with you, although sometimes the test (in my opinion) should guide you in the way you code. The case here is that in the constructor I'm calling another method that gives me a value, but this method is complicated so I don't want to call it in the Mockup to. Which is the best way to proceed? removing the final clause? calling this method outside the constructor? – iberbeu Feb 27 '13 at 11:13
  • Removing the final clause is not the way to go, in my opinion. I don't understand what "complicated" means. If you've already tested the "complicated" method and proved that it works, why can't you mock that to simply return the value you want and get on with it? – duffymo Feb 27 '13 at 12:22
  • With complicated I just mean that it is not just giving a value to the attribute. I've edited my question with a piece of code. In this case I should then remove the Singleton and mock the object GenericUtils, namely the method getTranslation(). In that way it must work. But what if the case were not to use a Singleton but calling a private method of the same class. How could I get rid of it? I cannot override that method... – iberbeu Feb 27 '13 at 14:42
2

If you wish to mock the class, give it an interface and mock the interface. Also, mocks aren't stubs. It sounds like you're creating a stub, rather than a mock. If you do wish to create a mock, pick a library that generates mocks for interfaces for you.

flup
  • 26,937
  • 7
  • 52
  • 74
  • I like your point of view, I didn't think of it. Is it really worth it to make an interface only for creating the Mockup? – iberbeu Feb 27 '13 at 11:17
  • The interface will also describe how both classes are coupled. I think this is always (well, very often) a good idea. – flup Feb 27 '13 at 11:20
  • In this particular case, it'll be a good first step in uncoupling the reference to the singleton. – flup Feb 27 '13 at 12:19
  • How do you do mocks without interfaces? That's what makes no sense. – duffymo Feb 27 '13 at 13:20
  • I have sometimes created mocks using interfaces, but in other cases what I usually do is to extend the class that I want to mock (In this case it would be: public class ReportsDataManagerMockup extends ReportsDataManager) and then override the methods i want. I think i missunderstood the terminology – iberbeu Feb 27 '13 at 13:53
1

In general I'd say that if a practice you use makes testing your code more difficult then the practice may be a smell.

Try to decide exactly what you want to achieve by setting variables final. Would protected be acceptable?

OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
1

You can sidestep the final restriction with standard reflection. Since you are in the context of a mockup, this wouldn't cause much problems, I suppose. Just beware of multithreading issues: the JVM will assume the field adheres to the final semantics and will optimize with that in mind.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
  • I don't really like this idea since using reflection is generally not recommended for unit testing, is it? – iberbeu Feb 27 '13 at 11:47
  • I don't know of such a recommendation. Anyway, what do you think all those mocking frameworks use? Reflection is quite mild compared to runrtime bytecode generation. – Marko Topolnik Feb 27 '13 at 12:00
  • Here you have a discussion about it: http://stackoverflow.com/questions/2811141/is-it-bad-practice-to-use-reflection-in-unit-testing Anyway using reflection for creating mocks could be a solution but doesn't it make more sense to use directly one of those already existing frameworks? – iberbeu Feb 27 '13 at 12:07
  • The point of the answer there is correct: if you test your code by invoking it over reflection, that's clearly a smell. If you use it to set up the test fixture, which is your case, that's perfectly fine. – Marko Topolnik Feb 27 '13 at 12:32
  • ok, you convinced me, but in my case I think I can do it in an easier way – iberbeu Feb 27 '13 at 13:37