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?

Xelian
  • 16,680
  • 25
  • 99
  • 152
  • Does this answer your question? [Private method in groovy is not private](https://stackoverflow.com/questions/7852370/private-method-in-groovy-is-not-private) – Raedwald Jun 25 '21 at 16:03

2 Answers2

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.

Community
  • 1
  • 1
Opal
  • 81,889
  • 28
  • 189
  • 210
  • 1
    Why is it not a good practice? Also in future, do you think groovy will take away support for this(accessing private methods)? – theprogrammer Jan 21 '20 at 18:16
  • @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. – Opal Jan 22 '20 at 16:04
  • 1
    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? – theprogrammer Jan 22 '20 at 17:47
  • 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? – Opal Jan 23 '20 at 13:05
  • 1
    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. :) – theprogrammer Jan 23 '20 at 16:10
  • 1
    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). – theprogrammer Jan 23 '20 at 16:11
  • Yes, only *public* contact. That's what I say: no testing of private methods, internals. Only public contract. – Opal Jan 23 '20 at 17:56
  • 2
    @theprogrammer, please also refer https://softwareengineering.stackexchange.com/a/100966/177830 and https://softwareengineering.stackexchange.com/a/375866/177830 and its comments to know why private methods should not be unit tested. – garnet Sep 17 '20 at 06:41
  • 1
    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. – PAX Sep 26 '20 at 11:43
-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.

Meower68
  • 929
  • 9
  • 21