Reputation: 980
I have:
SomeClass a = spy(SomeClass.class)
SomeClass
has private int myValue
.
I want to set myVlaue
to 3.
How can I do that using Mockito?
(If not possible with Mockito, what is my next best option preferably without having to discard my code that uses Mockito).
Notes:
getMyValue()
, I already know I can do that.setMyValue(int newMyValue)
, I do not want it.Upvotes: 3
Views: 21186
Reputation: 748
What exactly is a
in your test?
1) If a
is a dependency:
You shouldn't force an internal state onto it but configure the mock to return a desired value on a certain call, e.g. Mockito.doReturn("my current value is: 3").when(a).getText()
.
The basic idea behind that is that a unit test should be independend of the implementation of other units (and thereby also be independent of flaws in those implementations). Manipulation of a dependency's internal state causes close coupling of your test to another unit. The result would be a complex, hardly testable scenario.
2) If a
is your system under test:
You may provide an option to inject myValue
, e.g. a package private method setMyValue(final int value)
. A classic example would be inserting a timestamp provider into your system under test (e.g. Supplier<LocalDateTime>
) to inject a fix timestamp for testing (the test couldn't know which timestamp was used for a certain operation, so it would need to inject a fix timestamp for a well defined test scenario). Such utility methods for unit tests should be package private.
On a side note: Unit tests must be simple and easy to read and understand. Don't call a mock "a", use a name that fits the nature of it! Also I use to call the system under test "sut" in all my tests. Thus it is easy to distinguish between what's being tested and what's a dependency.
Upvotes: 0
Reputation: 41
Try the Following Code,
use org.springframework.test.util.ReflectionTestUtils
ReflectionTestUtils.setField(yourClass, "yourFieldName", yourFieldValue);
Upvotes: 2
Reputation: 95614
Reflection is the correct answer. Other than with @InjectMocks
or the recently removed internal class Whitebox, Mockito doesn't concern itself at all with fields, so you need to handle field access yourself or call setters on your spy.
As for rationale, I haven't seen one, but remember what Mockito does: It offers tooling and neat syntax to record and verify interactions—method calls, to be more specific—by internally creating a dynamic subclass (proxy) that overrides all methods. With fields there's nothing to record or verify, because the JVM just sets the value; working with fields would be a little out of Mockito's scope and introduce a lot of caveats about which fields can be changed (private? static? final?) and what you can do with them (not stub or verify multiple interactions).
Though Mockito doesn't explicitly recommend using getters, they are one of the few seams where you could override/track state accesses, so there's something to be said for using them all across Java for encapsulation's sake. If you can't set and read values like this:
mockitoMockWithFields.fieldA = 42;
return mockitoMockWithFields.fieldB;
Then all you're looking for Mockito to do is to defeat encapsulation or finality; Mockito can't do either natively, even for methods, so it's probably pretty reasonable for you to defeat those yourself or with a different library.
Upvotes: 2
Reputation: 980
The best option I came up with so far is reflection:
Field myVarField = SomeClass.class.getDeclaredField("myVarField");
myVarField.setAccessible(true);
myVarField.set(someClass,3);
Upvotes: 5