简体   繁体   中英

Change private member to default for testing

Is that good idea to change private class members to default(package access) for testing their behavior? I mean test case should destinate in test directory but in same package as tested member's class.

EDIT: All you guys tell the true. But classes have helper private methods often. And these methods can be complicated so need to be tested. And that is too bad - to test public methods for ensure correct working for private complicated methods. Don't you think so?

I generally prefer writing my classes and tests in a way that writing the tests against the public API makes sense. So basically I'm saying if you need to access the private state of your class under test you're probably already too involved in the internals of that class with your test..

No, it isn't. Because changing the test object may change the result. If you really need to call private members or methods during test, it's safer to add an accessor. This still changes the class, but with a lower risk. Example:

private void method() { /* ... */ }

// For testing purpose only, remove for production
@Deprecated  // just another way to create awareness ;)
void testMethod() {
   method();
}

OK - one more solution, if you need to test private methods: you can call any method with reflection and instantiation API.

Assuming, we have:

public class SomeClass {
  private Object helper(String s, String t) { /* ... +/ }
}

then we can test it like

@Test public void testHelper() {
   try {
     SomeClass some = new SomeClass();
     Method helperMethod = some.getClass().getDeclaredMethod("helper", String.class, String,class);
     helperMethod.setAccessible(true);
     Object result = helperMethod.invoke(some, "s", "t");
     // do some assert...

   catch(Exception e) {
     // TODO - proper exception handling
   }
}

I understand what you mean about needing to test private methods, and I also see why people say only test the public methods. I have just encountered some legacy code that has a lot of private methods, some of which are called by public methods, but some are threads, or called by threads, which are kicked off when the object is constructed. Since the code is riddled with bugs and lacks any comments I am forced to test the private code. I have used this method to address the issue.

   MainObject.cs
    class MainObject
    {
        protected int MethodOne();    // Should have been private.
        ....
    }
    TestMainObject.cs
    class ExposeMainObject : MainObject
    {
        public int MethodOne();
    }
    class TestMainObject
    {
        public void TestOne()
        {
        }
    }

Since the test objects aren't shipped I can't see a problem with it, but if there is please tell me.

Testing trumps privacy modifiers. Really, how often is a bug caused by having "a little too much" visibility for a method? Compared to bugs caused by a method that was not fully tested?

It would be nice if Java had a "friend" option, like C++. But a limitation in the language should never be an excuse for not testing something.

Michael Feathers chimes in on this debate in "Working Effectively with Legacy Code" (excellent book), and suggests that this may be a smell of a sub-class that wants to be extracted (and have public methods).

In our shop (~ 1M LOC), we replace 'private' with '/ TestScope /' as an indicator that a method should be effectively private, but still testable.

Trying to circumvent 'private' with reflection is IMHO a smell. It's making the tests harder to write, read, and debug in order to retain a 'fetish' of privacy, which you're working around anyway. Why bother?

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM