Unit testing with mock that has mock inside - java

I need to unit test a certain method that works on an object of type X. The X object has few normal fields like String, int etc. but it also has a List of types Y. This Y type is also quite complex. And to make my problem even more difficult, let's say that the type Y has another list of type Z.
Ideally, I need to mock object X, but tell it to inject another mock of type Y inside, which should also inject another mock Z to itself (to Y). How should I do that?
And if I have so many few-levels mocks how should I avoid writing 20 specifications of what these mocks should actually return upon calling their methods?
Or is this a type of problem where I should use Builders and actually build a real object?
Thanks alot,
Bob.
Edit:
just an example usage code on top from my head:
public String produceImportantStringOfImportantData(ObjectX x) throws ParseException {
StringBuilder textResult = new StringBuilder();
List<ObjectY> listOfY = x.getListOfY();
if (listOfY.isValid()) {
for (ObjectY y : listOfY) {
for (ObjectZ z : y.getListOfZ()) {
textResult.append("<font color='green'>").append(z.getField2).append("</font>").append(": ").append(z.getSomething())
.append(" Label : ").append(z.getParentComponent.getField()))
.append(" some important labels: ").append(z.getField()))
.append(" some important labels ").append(y.getAnotherField))
.append(" different, important label: ").append(y.getField()))
.append("<br/>");
}
}
}
return textResult.toString();
}

Assuming you are using some mocking framework like Mockito, you could simply do:
X mockX = Mockito.mock(X.class);
Y mockX = Mockito.mock(Y.class);
Z mockX = Mockito.mock(Z.class);
Mockito.when(mockY.getZ()).thenReturn(mockZ);
Mockito.when(mockX.getY()).thenReturn(mockY);
If this gets too deep (you mention 20 specifications), it could be a sign that you are violating the Law of Demeter or the Single Responsibility Principle. In this case it means that your classes execute too much logic themselves rather than accepting some processors in their constructor which do the actual work.
If you would do this, you can test the processors separately and easily, and testing the entire process.

Please don't use mocks for this as there's absolutely no need to, but as you already seem to be aware, will lead to painful and fragile tests.
Or is this a type of problem where I should use Builders and actually build a real object?
You don't even need a Builder (although I do recommend them) - just use a real object. Using a real object will lead to a test that's must more resilient to refactoring, will test what your code is actually doing and not just what you think it is.

Related

Java: Unit-Testing cascaded external interfaces

Consider a class that uses an external jar. The class processes objects of type D, which are obtained via objects A, B, and C, all of which external objects from the jar.
class DProcessor() {
public void process(PoolOfA pool) {
A a = pool.borrowObject()
...
B b = a.getB()
C c = b.getC()
for (D d : c.getAllDs()) {
// Do something meaningful with d
}
}
}
How do I Unit test process(PoolOfA pool)?
My best shot so far is writing mocks for all external classes:
PoolOfA pool = mock(PoolOfA.class);
A a = mock(A.class);
B b = mock(B.class);
C c = mock(C.class);
D d1 = mock(D.class);
D d2 = mock(D.class);
D d3 = mock(D.class);
D d4 = mock(D.class);
List listOfDs = new ArrayList<D>();
listOfDs.add(d1);
listOfDs.add(d2);
listOfDs.add(d3);
listOfDs.add(d4);
// Set specific behaviour for each d
when(pool.borrowObject()).thenReturn(a);
when(b.getC()).thenReturn(a);
when(c.getAllDs()).thenReturn(d);
when(b.getC()).thenReturn(c);
when(c.getAllDs()).thenReturn(listOfDs);
This seems cumbersome and inelegant. Is there a better way?
Better way is to rewrite the method, of course. But if you cannot do it for some reason, mockito offers great feature called 'deep stubs'. Check out the docs.
What process really does, is process some Ds in the loop. I would first make it clear by changing the signature:
public void process(Collection<D> allDs)
Now you can test that more easily by mocking D only.
That method can either be public if it can replace the existing one or package private for example if you don't want to expose it. In that latter case, you might still want to test that the other process method (the one that takes a poolOfA) properly extract the Ds. But that means that process(PoolOfA) needs to know a lot about the poolOfA which does not seem right.
This is one of the ideas promoted by this "Guide to writing testable code" which I think contains interesting concepts. What you mention would probably fall into the "Digging into Collaborators" section.
I would suggest a small redesign of the process method: It is currently responsible for doing two things: Extracting an Iterable of D's from the internals of the input and processing them.
So actually, you method, although declaring that it is expecting an input of type PoolOfA, is absolutely not interested in this object. It wants what's inside. I wold declare the method as taking an Iterable and pass the responsibility to the caller to give it the correct input. This will clarify the intention of the method and make it easier to test.
You may say: "this is not a real solution, this is just moving the problem to another location!
now I need to test the calling method!"
Well, yes and no. First, remember that you do not have to UT everything, just for the sake of coverage. You should focus your UT efforts on algorithmic pieces of code, it is OK to skip trivial object interactions.
If you insist, you can use more powerful mocking libraries like PowerMock in order to mock only past of your class, but this is a discussion for a different Question.

Value of Behavior Verification

I've been reading up on (and experimenting with) several Java mocking APIs such as Mockito, EasyMock, JMock and PowerMock. I like each of them for different reasons, but have ultimately decided on Mockito. Please note though, that this is not a question about which framework to use - the question really applies to any mocking framework, although the solution will look different as the APIs are (obviously) different.
Like many things, you read the tutorials, you follow the examples, and you tinker around with a few code samples in a sandbox project. But then, when it comes time to actually use the thing, you start to choke - and that's where I am.
I really, really like the idea of mocking. And yes, I am aware of the complaints about mocking leading to "brittle" tests that are too heavily coupled with the classes under test. But until I come to such a realization myself, I really want to give mocking a chance to see if it can add some good value to my unit tests.
I'm now trying to actively use mocks in my unit tests. Mockito allows both stubbing and mocking. Let's say we have a Car object that has a getMaxSpeed() method. In Mockito, we could stub it like so:
Car mockCar = mock(Car.class);
when(mockCar.getMaxSpeed()).thenReturn(100.0);
This "stubs" the Car object to always return 100.0 as the max speed of our car.
My problem is that, after writing a handful of unit tests already...all I'm doing is stubbing my collaborators! I'm not using a single mock method (verify, etc.) available to me!
I realize that I'm stuck in a "stubbing state of mind" and I'm finding it impossible to break. All this reading, and all this excitement building up to using mocks in my unit testing and... I can't think of a single use case for behavior verification.
So I backed up and re-read Fowler's article and other BDD-style literatures, and still I'm just "not getting" the value of behavior verification for test double collaborators.
I know that I'm missing something, I'm just not sure of what. Could someone give me a concrete example (or even a set of examples!) using, say, this Car class, and demonstrate when a behavior-verifying unit test is favorable to a state-verifying test?
Thanks in advance for any nudges in the right direction!
Well, if the object under test calls a collaborator with a computed value, and the test is supposed to test that the computation is correct, then verifying the mock colaborator is the right thing to do. Example:
private ResultDisplayer resultDisplayer;
public void add(int a, int b) {
int sum = a + b; // trivial example, but the computation might be more complex
displayer.display(sum);
}
Clearly, in this case, you'll have to mock the displayer, and verify that its display method has been called, with the value 5 if 2 and 3 are the arguments of the add method.
If all you do with your collaborators is call getters without arguments, or with arguments which are direct inputs of the tested method, then stubbing is probably sufficient, unless the code might get a value from two different collaborators and you want to verify that the appropriate collaborator has been called.
Example:
private Computer noTaxComputer;
private Computer taxComputer;
public BigDecimal computePrice(Client c, ShoppingCart cart) {
if (client.isSubjectToTaxes()) {
return taxComputer.compute(cart);
}
else {
return noTaxComputer.compute(cart);
}
}
I like #JB Nizet's answer, but here's another example. Suppose you want to persist a Car to a database using Hibernate after making some changes. So you have a class like this:
public class CarController {
private HibernateTemplate hibernateTemplate;
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public void accelerate(Car car, double mph) {
car.setCurrentSpeed(car.getCurrentSpeed() + mph);
hibernateTemplate.update(car);
}
}
To test the accelerate method, you could just use a stub, but you wouldn't have a compete test.
public class CarControllerTest {
#Mock
private HibernateTemplate mockHibernateTemplate;
#InjectMocks
private CarController controllerUT;
#Test
public void testAccelerate() {
Car car = new Car();
car.setCurrentSpeed(10.0);
controllerUT.accelerate(car, 2.5);
assertThat(car.getCurrentSpeed(), is(12.5));
}
}
This test passes and does check the computation, but we don't know if the car's new speed was saved or not. To do that, we need to add:
verify(hibernateTemplate).update(car);
Now, suppose that if you try to accelerate past max speed, you expect the acceleration and the update not to happen. In that case, you would want:
#Test
public void testAcceleratePastMaxSpeed() {
Car car = new Car();
car.setMaxSpeed(20.0);
car.setCurrentSpeed(10.0);
controllerUT.accelerate(car, 12.5);
assertThat(car.getCurrentSpeed(), is(10.0));
verify(mockHibernateTemplate, never()).update(car);
}
This test will not pass with our current implementation of CarController, but it shouldn't. It shows you need to do more work to support this case and that one of the requirements is that you don't try to write to the database in this case.
Basically, verify should be used for exactly what it sounds like - to verify that something happened (or didn't happen). If the fact that it happened or didn't isn't really what you are trying to test, then skip it. Take the second example I made. One could argue that since the value wasn't changed, it doesn't really matter whether update was called or not. In that case, you can skip the verify step in the second example since the implementation of accelerate would be correct either way.
I hope it doesn't sound like I'm making a case for using verify a lot. It can make your tests very brittle. But it can also 'verify' that important things that were supposed to happen did happen.
My take on this is that every test case should contain EITHER
stubbing, plus one or more asserts OR
one or more verifys .
but not both.
It seems to me that in most test classes, you end up with a mixture of "stub and assert" test cases and "verify" test cases. Whether a test case does a "stub and assert" or does a "verify" depends on whether the value returned by a collaborator is important to the test. I need two examples to illustrate this.
Suppose I have an Investment class, which has a value in dollars. Its constructor sets the initial value. It has an addGold method, which increases the value of an Investment by the amount of gold times the price of gold in dollars per ounce. I have a collaborator called PriceCalculator that calculates the price of gold. I might write a test like this.
public void addGoldIncreasesInvestmentValueByPriceTimesAmount(){
PriceCalculator mockCalculator = mock( PriceCalculator.class );
when( mockCalculator.getGoldPrice()).thenReturn( new BigDecimal( 400 ));
Investment toTest = new Investment( new BigDecimal( 10000 ));
toTest.addGold( 5 );
assertEquals( new BigDecimal( 12000 ), toTest.getValue());
}
In this case, the result from the collaborator method is important to the test. We stub it, because we're not testing the PriceCalculator at this point. There's no need to verify, because if the method hadn't been called, the final value of the investment value would not be correct. So all we need is the assert.
Now, suppose there's a requirement that the Investment class notifies the IRS whenever anyone withdraws more than $100000 from an Investment. It uses a collaborator called IrsNotifier to do this. So a test for this might look like this.
public void largeWithdrawalNotifiesIRS(){
IrsNotifier mockNotifier = mock( IrsNotifier.class );
Investment toTest = new Investment( new BigDecimal( 200000 ));
toTest.setIrsNotifier( mockNotifier );
toTest.withdraw( 150000 );
verify( mockNotifier ).notifyIRS();
}
In this case, the test doesn't care about the return value from the collaborator method notifyIRS(). Or maybe it's void. What matters is just that the method got called. For a test like this, you'll use a verify. There may be stubbing in a test like this (to set up other collaborators, or return values from different methods), but it's unlikely that you'll ever want to stub the same method that you verify.
If you find yourself using both stubbing and verification on the same collaborator method, you should probably ask yourself why. What is the test really trying to prove? Does the return value matter to the test? Because this is usually a testing code smell.
Hope these examples are helpful to you.

Pros and cons of casting vs. providing a method that returns the required type (Java)

I'm doing a bit of playing about to learn a framework I'm contributing to, and an interesting question came up. EDIT: I'm doing some basic filters in the Okapi Framework, as described in this guide, note that the filter must return different event types to be useful, and that resources must be used by reference (as the same resource may be used in other filters later). Here's the code I'm working with:
while (filter.hasNext()) {
Event event = filter.next();
if (event.isTextUnit()) {
TextUnit tu = (TextUnit)event.getResource();
if (tu.isTranslatable()) {
//do something with it
}
}
}
Note the cast of the resource to a TextUnit object on line 4. This works, I know it's a TextUnit because events that are isTextUnit() will always have a TextUnit resource. However, an alternative would be to add an asTextUnit() method to the IResource interface that returns the event as a TextUnit (as well as equivalent methods for each common resource type), so that the line would become:
TextUnit tu = event.getResource().asTextUnit;
Another approach might be providing a static casting method in TextUnit itself, along the lines of:
TextUnit tu = TextUnit.fromResource(event.getResource());
My question is: what are some arguments for doing it one way or the other? Are there performance differences?
The main advantage I can think of with asTextUnit() (or .fromResource) is that more appropriate exceptions could be thrown if someone tries to get a resource as the wrong type (i.e. with a message like "Cannot get this RawDocument type resource as a TextUnit - use asRawDocument()" or "The resource is not a TextUnit").
The main disadvantages I can think of with .asTextUnit() is that each resource type would then have to implement all the methods (most of which will just throw an exception), and if another major resource type is added there would be some refactoring to add the new method to every resource type (although there's no reason the .asSomething() methods would have to be defined for every possible type, the less common resources could just be cast, although this would lead to inconsistency of approach). This wouldn't be a problem with .fromResource() since it's just one method per type, and could be added or not per type depending on preference.
If the aim is to test an object's type and cast it, then I don't see any value in creating / using custom isXyz and asXyz methods. You just end up with a bunch of extra methods that make little difference to code readability.
Re: your point about appropriate exception messages, I would say that it is most likely not worth it. It is reasonable to assume that not having a TextUnit when a TextUnit is expected is symptom of a bug somewhere. IMO, it is not worthwhile trying to provide "user friendly" diagnostics for bugs. The person that the information is aimed at is a Java programmer, and for that person the default message and stacktrace for a regular ClassCastException (and the source code) provides all of the information required. (Translating it into pretty language adds no real value.)
On the flip-side, the performance differences between the two forms are not likely to be significant. But consider this:
if (x instanceof Y) {
((Y) x).someYMethod();
}
versus
if (x.isY()) {
x.asY().someYMethod();
}
boolean isY(X x) { return x instanceof Y; }
Y asY(X x) { return (Y) x; }
The optimizer might be able to do a better job of the first compared with the second.
It might not inline the method calls in the second case, especially if it is changed to use instanceof and throw a custom exception.
It is less likely to figure out that only one type test is really required in the second case. (It might not in the first case either ... but it is more likely to.)
But either way, the performance difference is going to be small.
Summary, the fancy methods are not really worth the effort, though they don't do any real harm.
Now if the isXyz or asXyz methods were testing the state of the object (not just the object's Java type), or if the asXyz was returning a wrapper, then the answers would be different ...
You could also just go
if (event instanceof TextUnit) {
// ...
}
and save yourself the trouble.
To answer your question regarding whether to go asTextUnit() vs. TextUnit.fromResource, the performance difference would depend upon how you actually implement these methods.
In the case of the static converter you would have a to create and return a new object of type TextUnit. However, in the case of the member function you could simply return this casted or you could create an return a new object - depends upon your use case.
Either ways, seems like instanceof is probably the cleanest way here.
What if your filter were extended - or wrapped - to return only text unit events? In fact, what if it returned only the resources of text unit events? Then your loop would be much simpler. I would think the clean way to do this would be a second filter, which simply returned just the text unit events, followed by, let's say, an Extractor, which returned the properly cast resource.
If you have a common base class, you can have a single asXMethod there for every derived class, and needn't refactor all derived classes:
abstract class Base {
A asA () { throw new InstantiationException ("not an A"); }
B asB () { throw new InstantiationException ("not an B"); }
C asC () { throw new InstantiationException ("not an C"); }
// much more ...
}
class A extends Base {
A asA () { /* hard work */ return new A (); }
// no asB, asC requiered
}
class B extends Base {
B asB () { /* hard work */ return new B (); }
// no asA, asC required
}
// and so on.
looks pretty clever. For a new Class N, just add a new Method to Base, and all derived classes get it. Just N needs to implement asN.
But it smells.
Why should a B have a method asA if it will always fail? That's not a good design. Exceptions in the generator are cheap, if they aren't triggered. Only thrown exceptions might be costly.
Yes, there are differences. Creating new immutable elements is better then casting. Pass all serializable data (non transient or computable data) to a Builder and build appropriate class.

java: combined instanceof and cast?

(Please no advise that I should abstract X more and add another method to it.)
In C++, when I have a variable x of type X* and I want to do something specific if it is also of type Y* (Y being a subclass of X), I am writing this:
if(Y* y = dynamic_cast<Y*>(x)) {
// now do sth with y
}
The same thing seems not possible in Java (or is it?).
I have read this Java code instead:
if(x instanceof Y) {
Y y = (Y) x;
// ...
}
Sometimes, when you don't have a variable x but it is a more complex expression instead, just because of this issue, you need a dummy variable in Java:
X x = something();
if(x instanceof Y) {
Y y = (Y) x;
// ...
}
// x not needed here anymore
(Common thing is that something() is iterator.next(). And there you see that you also cannot really call that just twice. You really need the dummy variable.)
You don't really need x at all here -- you just have it because you cannot do the instanceof check at once with the cast. Compare that again to the quite common C++ code:
if(Y* y = dynamic_cast<Y*>( something() )) {
// ...
}
Because of this, I have introduced a castOrNull function which makes it possible to avoid the dummy variable x. I can write this now:
Y y = castOrNull( something(), Y.class );
if(y != null) {
// ...
}
Implementation of castOrNull:
public static <T> T castOrNull(Object obj, Class<T> clazz) {
try {
return clazz.cast(obj);
} catch (ClassCastException exc) {
return null;
}
}
Now, I was told that using this castOrNull function in that way is an evil thing do to. Why is that? (Or to put the question more general: Would you agree and also think this is evil? If yes, why so? Or do you think this is a valid (maybe rare) use case?)
As said, I don't want a discussion whether the usage of such downcast is a good idea at all. But let me clarify shortly why I sometimes use it:
Sometimes I get into the case where I have to choose between adding another new method for a very specific thing (which will only apply for one single subclass in one specific case) or using such instanceof check. Basically, I have the choice between adding a function doSomethingVeryVerySpecificIfIAmY() or doing the instanceof check. And in such cases, I feel that the latter is more clean.
Sometimes I have a collection of some interface / base class and for all entries of type Y, I want to do something and then remove them from the collection. (E.g. I had the case where I had a tree structure and I wanted to delete all childs which are empty leafs.)
Starting Java 14 you should be able to do instanceof and cast at the same time. See https://openjdk.java.net/jeps/305.
Code example:
if (obj instanceof String s) {
// can use s here
} else {
// can't use s here
}
The variable s in the above example is defined if instanceof evaluates to true. The scope of the variable depends on the context. See the link above for more examples.
Now, I was told that using this castOrNull function in that way is an evil thing do to. Why is that?
I can think of a couple of reasons:
It is an obscure and tricky way of doing something very simple. Obscure and tricky code is hard to read, hard to maintain, a potential source of errors (when someone doesn't understand it) and therefore evil.
The obscure and tricky way that the castOrNull method works most likely cannot be optimized by the JIT compiler. You'll end up with at least 3 extra method calls, plus lots of extra code to do the type check and cast reflectively. Unnecessary use of reflection is evil.
(By contrast, the simple way (with instanceof followed by a class cast) uses specific bytecodes for instanceof and class casting. The bytecode sequences can almost certainly will be optimized so that there is no more than one null check and no more that one test of the object's type in the native code. This is a common pattern that should be easy for the JIT compiler to detect and optimize.)
Of course, "evil" is just another way of saying that you REALLY shouldn't do this.
Neither of your two added examples, make use of a castOrNull method either necessary or desirable. IMO, the "simple way" is better from both the readability and performance perspectives.
In most well written/designed Java code the use of instanceof and casts never happens. With the addition of generics many cases of casts (and thus instanceof) are not needed. They do, on occasion still occur.
The castOrNull method is evil in that you are making Java code look "unnatural". The biggest problem when changing from one language to another is adopting the conventions of the new language. Temporary variables are just fine in Java. In fact all your method is doing is really hiding the temporary variable.
If you are finding that you are writing a lot of casts you should examine your code and see why and look for ways to remove them. For example, in the case that you mention adding a "getNumberOfChildren" method would allow you to check if a node is empty and thus able to prune it without casting (that is a guess, it might not work for you in this case).
Generally speaking casts are "evil" in Java because they are usually not needed. Your method is more "evil" because it is not written in the way most people would expect Java to be written.
That being said, if you want to do it, go for it. It isn't actually "evil" just not "right" way to do it in Java.
IMHO your castOrNull is not evil, just pointless. You seem to be obsessed with getting rid of a temporary variable and one line of code, while to me the bigger question is why you need so many downcasts in your code? In OO this is almost always a symptom of suboptimal design. And I would prefer solving the root cause instead of treating the symptom.
I don't know exactly why the person said that it was evil. However one possibility for their reasoning was the fact that you were catching an exception afterwards rather than checking before you casted. This is a way to do that.
public static <T> T castOrNull(Object obj, Class<T> clazz) {
if ( clazz.isAssignableFrom(obj.getClass()) ) {
return clazz.cast(obj);
} else {
return null;
}
}
Java Exceptions are slow. If you're trying to optimize your performance by avoiding a double cast, you're shooting yourself in the foot by using exceptions in lieu of logic. Never rely on catching an exception for something you could reasonably check for and correct for (exactly what you're doing).
How slow are Java exceptions?

Premature optimization in Java: when to use "x = foo.getX()" vs simply "foo.getX()"

When I find myself calling the same getter method multiple times, should this be considered a problem? Is it better to [always] assign to a local variable and call only once?
I'm sure the answer of course is "it depends".
I'm more concerned about the simpler case where the getter is simply a "pass-along-the-value-of-a-private-variable" type method. i.e. there's no expensive computation involved, no database connections being consumed, etc.
My question of "is it better" pertains to both code readability (style) and also performance. i.e. is it that much of a performance hit to have:
SomeMethod1(a, b, foo.getX(), c);
SomeMethod2(b, foo.getX(), c);
SomeMethod3(foo.getX());
vs:
X x = foo.getX();
SomeMethod1(a, b, x, c);
SomeMethod2(b, x, c);
SomeMethod3(x);
I realize this question is a bit nit-picky and gray. But I just realized, I have no consistent way of evaluating these trade-offs, at all. Am fishing for some criteria that are more than just completely whimsical.
Thanks.
The choice shouldn't really be about performance hit but about code readability.
When you create a variable you can give it the name it deserves in the current context. When you use a same value more than one time it has surely a real meaning, more than a method name (or worse a chain of methods).
And it's really better to read:
String username = user.getName();
SomeMethod1(a, b, username, c);
SomeMethod2(b, username, c);
SomeMethod3(username);
than
SomeMethod1(a, b, user.getName(), c);
SomeMethod2(b, user.getName(), c);
SomeMethod3(user.getName());
For plain getters - those that just returns a value - HotSpot inlines it in the calling code, so it will be as fast as it can be.
I, however, have a principle about keeping a statement on a single line, which very often results in expressions like "foo.getBar()" being too long to fit. Then it is more readable - to me - to extract it to a local variable ("Bar bar = foo.getBar()").
They could be 2 different things.
If GetX is non-deterministic then the 1st one will give different results than the 2nd
Personally, I'd use the 2nd one. It's more obvious and less unnecessarily verbose.
I use the second style if it makes my code more readable or if I have to use the assigned value again. I never consider performance (on trivial things) unless I have to.
That depends on what getX() actually does. Consider this class:
public class Foo {
private X x;
public X getX() { return x; }
}
In this case, when you make a call to foo.getX(), JVM will optimize it all the way down to foo.x (as in direct reference to foo's private field, basically a memory pointer). However, if the class looks like this:
public class Foo {
private X x;
public X getX() { return cleanUpValue(x); }
private X cleanUpValue(X x) {
/* some modifications/sanitization to x such as null safety checks */
}
}
the JVM can't actually inline it as efficiently anymore since by Foo's constructional contract, it has to sanitize x before handing it out.
To summarize, if getX() doesn't really do anything beyond returning a field, then there's no difference after initial optimization runs to the bytecode in whether you call the method just once or multiple times.
Most of the time I would use getX if it was only once, and create a var for it for all other cases. Often just to save typing.
With regards to performance, the compiler would probably be able to optimize away most of the overhead, but the possibility of side-effects could force the compiler into more work when doing multiple method-calls.
I generally store it locally if:
I'm will use it in a loop and I don't want or expect the value to change during the loop.
I'm about to use it in a long line of code or the function & parameters are very long.
I want to rename the variable to better correspond to the task at hand.
Testing indicates a significant performance boost.
Otherwise I like the ability to get current values and lower level of abstraction of method calls.
Two things have to be considered:
Does the call to getX() have any side effects? Following established coding patterns, a getter should not alter the object on which it is called, the in most cases, there is no side effect. Therefore, it is semantically equivalent to call the getter once and store the value locally vs. calling the getter multiple times. (This concept is called idempotency - it does not matter whether you call a method once or multiple times; the effect on the data is exactly the same.)
If the getter has no side effect, the compiler can safely remove subsequent calls to the getter and create the temporary local storage on its own - thus, the code remains ultra-readable and you have all the speed advantage from calling the getter only once. This is all the more important if the getter does not simply return a value but has to fetch/compute the value or runs some validations.
Assuming your getter does not change the object on which it operates it is probably more readable to have multiple calls to getX() - and thanks to the compiler you do not have to trade performance for readability and maintainability.

Categories