TDD and Mockito testing newb here... I have recently discovered about injection of mocks of private fields and am trying to get my ideas straight.
It may well be that my thinking on this particular matter is all wrong, but it's just that I often find a situation where I want to test that calling a particular method has resulted in a private field being assigned: before the call it was null
, and after the call it is set to an instance of whatever class.
A mocked private field is a subclass of the class in question by the time you start to run your test method, so obviously testing for null
is meaningless/doesn't work. Equally, if your method results in an assignment of this field this means that the mock variable has been replaced by a genuine instance. Thus, even if methods are called on it it won't lead to any interaction with the mock variable. In any event, if the test is just to check on the creation and assignment there is no reason you would want to have any interaction with it in the test.
Obviously one answer is to create a public
get()
method or a public
create()
method in the app class. But this gives me a bad feeling as it is clearly just being done for testing purposes.
Incidentally there will be those, many no doubt much more experienced than me at TDD, who will say that I'm getting too fine-grained and shouldn't be testing something as specific as assignment of a field. But my understanding of the most extreme approach to TDD is "don't write a line of code without a test". I really am trying to stick with this at this stage as far as possible. With experience maybe I will have greater understanding of how and when to depart from this principle.
It's just that assignment of a field seems to me to be a "class event" (of the host class) as worthy as any other type of event, such as a call of a method on the field once an instance has been assigned to the field. Shouldn't we be able to test for it in some way...? What do the Mockito pros who accept that this may be a legitimate thing to test for do in these circumstances?
later...
The comment from Fabio highlights the tension which, as a newb, I find puzzling, between "never write a line without a test" and "test only public methods": the effect of this is inevitably to expose much more stuff than I want, purely for the sake of testing.
And what he says about "changing tests all the time" I also find problematic: if we inject mocked private fields, and use them, then we are going to have to change the tests if we change the "implementation details". Nor does this idea fill me with dread: a need for change is perceived, you look at the very explanatory names of your existing test methods and decide which ones no longer apply, and of course you create new ones... the testing code, like the app code, will have to change all the time, right?
Isn't the testing code like some sort of die or mould, which guides and constrains the app code but at the same time can be detached from it? By Mockito allowing us to mock private fields a privileged form of access is already granted... who's to say how far this privileged access should rightly extend?
even later...
Jeff Bowman suggests this is a dup with this . I'm not entirely convinced, since I am asking a very specific thing for which it's just possibly there may be a specific answer (some Mockito means of detecting assignment). But his answer there seems very comprehensive and I'm trying to fully understand it all... including the whole dependency injection thing... and the compromises you seem have to make in "distorting" your public interface to make an app class as testable as you want to make it.
Simple example: you need to write a class Class1
with two methods Method1
and Method2
which return values provided by some Helper
class.
Class1
and Method1 - compile ok and test fail Helper
and call some of this methods which return expected value - test pass Method1
- test fail Method1
to satisfy both test cases - tests are green Method1
if you see possibility - test must stay green Method2
which will update some public field Field1
of Class1
- will not compile Method2
and field Field1
in Class1
- compile - ok, test fail Helper
class in Method2
, call it method and update Field1
with expected value - test pass Method2
- test fail Method2
to satisfy both test cases - tests are green Now you have implemented needed behavior and noticed that both Method1
and Method2
create instance of Helper
class.
Helper
and use it in both methods - all tests are failed - because your private field not instantiated. Later if you decide to move creation of Helper
class outside and pass it to the Class1
as constructor's parameter, you just change your production code and tests will show you does you break anything without changing tests.
Main point of my answer, that if you think like "I want write this line of code - How I can test it" - it will goes you in thats kind of situation you got right now.
Try to first think what you want to test and after writing the test think how you will implement it.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.