Why can test private methods/fields in Spock without problems?
Asked Answered
F

2

8
package com.example.dev;
public class AClass {
 private Integer a =10;
...//other code
}

and when I try to access a in my Spock method:

package com.example.dev;
def 'test a'() {
 AClass aClassVar = new AClass()
 aClassVar.a = new Integer(100);
...//other testing stuff
}

It works fine. Why this happens? Is Spock use reflection for accessing the private fields? Or my encapsulation in not written well?

Frodin answered 20/10, 2014 at 11:49 Comment(1)
Does this answer your question? Private method in groovy is not privateBlaney
A
10

Spock isn't guilty, it's groovy itself, see: Private method in groovy is not private.

While it's possible to refer to private members of class, it's definitely not a good practice.

Arcuation answered 20/10, 2014 at 11:56 Comment(9)
Why is it not a good practice? Also in future, do you think groovy will take away support for this(accessing private methods)?Eisenstark
@theprogrammer, I doubt if it's going to be removed. When it comes to testing private methods, when you do it you test internals of the class not its public contract. It may change, and your tests mail fail.Arcuation
Internals of the class? If we can test private methods, we can definitely test their contract as well(like what they return based on inputs etc thanks to groovy). And if in future, the return type etc changes, then of course the test will fail. This is true even for public methods. I still dont see how this is a bad practice? Maybe you meant to say that by testing private methods(using groovy's magic syntax etc), it might not be secure?Eisenstark
Ok, imagine that you have a class that provides getData() method. It's public. Underneath it fetches data over HTTP. You've implemented tests for the HTTP-based internals. Now, you substitute HTTP with a DB. You tests are now useless, you need to reimplement them. What for?Arcuation
Won't we still stub the underneath services and only test getData's contract? If the contract changes, then its a valid scenario to redo the tests. I am saying that even if the method which was supposed to be private(getData) ends up being public or is tested using groovy magic, we will still follow testing conventions and only test its contract right? Just because its a private method, doesn't mean we will break unit testing conventions. Sorry if I am misunderstanding. Thanks for the reply. :)Eisenstark
If getData was indeed supposed to be public and we did what you say, then our testing conventions are bad. While unit testing why are we not stubbing Http-based internals or other dependencies that method needs? During this unit test, shouldnt we only test getData assuming that all dependencies work as per their contract(the http method I mean).Eisenstark
Yes, only public contact. That's what I say: no testing of private methods, internals. Only public contract.Arcuation
@theprogrammer, please also refer softwareengineering.stackexchange.com/a/100966/177830 and softwareengineering.stackexchange.com/a/375866/177830 and its comments to know why private methods should not be unit tested.Ovariectomy
I agree with @theprogrammer. Sometimes you would like to perform a detailed test on private method behaviors and it's nerve racking if you are forced to modify their visibility to package private/etc. only to provide access for testing! Private visibility doesn't mean that it's not worth to test this method's contract, especially when its implementation is complex and error prone.Kyle
I
-2

It's my understanding that

aClassVar.a = new Integer(100)

in Groovy / Spock is just syntactic sugar for

aClassVar.setA(new Integer(100));

in Java. There have been occasions where I tried to do that and there WASN'T a setter and Spock griped.

As for why we create private attributes and then give them setters, THAT is another discussion.

Indole answered 13/9, 2016 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.