Discussions

News: Testing private methods, TDD, and test-driven refactoring

  1. While being a TDD--Test Driven Development--coach, Paulo Caroli always asked about testing private methods. He finally decided to write about his experience on testing private methods. When really doing TDD (i.e. writing the test code before writing the functional code, and then refactoring the code) private methods are guaranteed to be test covered. When driving the functional code design and implementation from the unit test (aka Test Driven Development), no method is created private. Instead, the private methods are extracted—extract method refactoring step--from a public or package level method. The Example 1 below presents a scenario on applying TDD and how the private method is created. New code development following TDD Example 1: new code development following TDD Consider the development example following a TDD sequence for creating methodA and methodB. create testMethodA/ create methodA/ refactoring create testMethodB/ create methodB/ refactoring: extract methodC On the first sequence, the testMethodA is created for validating the functionality expected of methodA. The methodA is successfully created: All tests including the testMethodA are passing. Then you look for improvements in the code; refactoring. On the second sequence, the testMethodB is created for validating the functionality expected of methodB. The methodB is successfully created. All tests including the testMethodB are passing. Then you look for improvements in the code; refactoring. While looking for improvements in the TDD Refactoring step, you recognize that methodA and methodB have a common fragment of code (code duplication). You extract the common code fragment into a private method whose name explains the purpose of the method--methodC. Then methodA and methodB invoke methodC. In this example testMethodA covers methodA, which invokes private methodC; therefore the private methodC is test covered. Please keep in mind that this is a simplified example. Your methods and tests should not read like testMethodA / methodA, and testMethodB / methodB. Jeff Patton describes how test cases can describe design in his Test-Driven Development Isn’t Testing paper. When doing TDD, the private methods emerge from your code. And because you test-drive your development, no functionality is added without a test. So, for code fully developed by following TDD you won’t have to test the private method separately: Private methods are already being tested by previously written tests. Read the rest here: http://agiletips.blogspot.com/2008/11/testing-private-methods-tdd-and-test.html .
  2. I disagree. Testing private methods makes finding errors easier. If I have a properly tested private method, and I reuse the method in a more complex method, any error I find during testing is likely the result of the new code. I'm not arguing that one can't live without test on private methods, only that in my experience it makes live easier. Also, the premise that one "extracts" private methods is not entirely true. Sure, this happens from frequently, but in many cases functionality can grow from the bottom up. I would not generalize. Mark
  3. I suspect his point is more that if you are doing fully test-driven development, the functionality in your private methods is already fully coverered by tests. To put it another way, if you are doing pure TDD and you have functionality that isn't there to support a test (and hence being tested), why is it there at all? If you are building your class from the bottom up, private methods first, he would probably contend that you aren't doing TDD :-)
  4. Also, the premise that one "extracts" private methods is not entirely true. Sure, this happens from frequently, but in many cases functionality can grow from the bottom up. I would not generalize.
    I would like to see how this "bottom up" growth occurs. Is this code growth really driven with tests? In my TDD experience, private methods just don't come into being. The only code that comes into being is the code driven by the test. Typically that starts out as code in a publicly accessible method. Some of that code may migrate to private methods over time, but it never starts out as privately accessible. The design of the class is driven by the tests. -- chris --
  5. Very few people ever get the chance to build a system completely from scratch. In a large, complex, enterprise-size application, the unit test coverage may be spotty or non-existent. In that case, you'll likely add unit tests to the private methods. Now, I understand that the article is primarily focused on "pure" TDD. In theory, tests on public methods only should cover all your needs. However, I suspect that very few developers actually practice "pure" TDD. I certainly don't. As such, coding can be a combination of TDD, and bottom up development.
  6. Also, the premise that one "extracts" private methods is not entirely true. Sure, this happens from frequently, but in many cases functionality can grow from the bottom up. I would not generalize.


    I would like to see how this "bottom up" growth occurs. Is this code growth really driven with tests? In my TDD experience, private methods just don't come into being. The only code that comes into being is the code driven by the test. Typically that starts out as code in a publicly accessible method. Some of that code may migrate to private methods over time, but it never starts out as privately accessible. The design of the class is driven by the tests.

    -- chris --
    TDD does not imply that *every* method comes into existence through refactoring. One can certainly add helper methods on the fly without having to extract the code. For example, my approach typically involves coding the algorithm as a series of calls to helper methods. So: int calculateX() { return 0; } Becomes: int calculateX() { a(); b(); c() return 0; } where a(), b(), and c() represent the highest level steps of the algorithm. At this point, I would define unit tests for each helper method, and in turn, descend into each method, typically in a depth first manner. Remember that refactoring is a mechanism for making your design cleaner and more readable. It's not an excuse for skipping design altogether. I don't believe that one should extend the YAGNI principle to the point where one can never write a line of code unless it's embedded in an existing method first, and then extracted. Mark
  7. Go ahead and test the submethods[ Go to top ]

    The author of the blog realizes that you need to test private methods if there is not already test coverage. "If you are improving a legacy code, you should be following Test-Driven Refactoring. In this case, you may provisionally add tests for private methods. " He only says that typically one may end up with private methods which don't have a specific test when doing TDD. I have a problem with this line of thinking because I worked at a place where the boss said that unit tests should only test the public interface. And I think that is ridiculous. For example, assume I have the below code float multiply(float x, float y) { return x * y; } float add(float x, float y) { return x + y; } float subtract(float x, float y) { return x - y; } float equation(float x, float y) { float multiply = multiply(x, y); float add = add(multiply, 3.0f); float multiply2 = multiply(x,add); return subtract(multiply2, 7.0f); } I would much rather write testMultiply(), testAdd(), testSubstract() for the simple building block methods and then I am confident that my equation() method will have a good chance of working correctly so then I can write a more simple testEquation() method that just checks a few cases. If I am forced to only test the equation method then my test will be much more difficult to write (so I may not write it) and will probably have far less coverage that my individual tests. In my opinion it is far better and easier to just make the private methods protected and go ahead and test them so you have confidence that the more complex method has a good foundation. Of course the building block methods will be more complex in real code.
  8. Re: Go ahead and test the submethods[ Go to top ]

    I've heard people argue that you should never use private methods because perhaps they belong in another unit after all. Regardless of your view on this I've seen many times that people change their private methods to protected or package private just so that they become possible to test or mock. If you can motivate the use of private methods and motivate the need to test them in separation I think that you should. It then usually comes down to the technical complexity needed to test these methods if you don't want to change the method modifiers. If you like you can checkout PowerMock which can assist you with testing and even mocking private methods (it also does a lot of other stuff like mocking static and final methods, new instance calls etc etc).
  9. Re: Go ahead and test the submethods[ Go to top ]

    I've heard people argue that you should never use private methods because perhaps they belong in another unit after all. Regardless of your view on this I've seen many times that people change their private methods to protected or package private just so that they become possible to test or mock. If you can motivate the use of private methods and motivate the need to test them in separation I think that you should. It then usually comes down to the technical complexity needed to test these methods if you don't want to change the method modifiers. If you like you can checkout PowerMock which can assist you with testing and even mocking private methods (it also does a lot of other stuff like mocking static and final methods, new instance calls etc etc).
    I agree that methods should generally be protected, and not private. This makes reusing the code a lot easier. However, one should *not* make a method non-private simply because one wants to write a unit test for the method. For years I've advocated using static inner classes for structuring unit tests. Because static inner classes reside within the class under test, they have access to all private members and methods. Also, since they live with the code, they're more likely to stay up-to-date. Tests that live in separate packages have a tendency to degrade over time. Mark
  10. Untested methods are untested code[ Go to top ]

    When testing code, you test for valid and invalid data. So untested private methods (directly) are untested code. It's as simple as that.
  11. Re: Untested methods are untested code[ Go to top ]

    When testing code, you test for valid and invalid data.

    So untested private methods (directly) are untested code. It's as simple as that.
    That's a valid point. However, I have the feeling that the author of the article would argue that the tests for the public methods should include invalid data. As another poster pointed out, it starts to get real messy when you're forced to code all the variations at the public method level. The whole issue is not black and white. Unit tests are there to give you confidence, as well as document the usage of the methods to programmers that come after you. When in doubt, add a test if you think it makes things easier. Insisting that unit tests *only* exist for public methods smacks of inflexibility. I believe Ron Jeffries once said, "Just because you're doing XP is not an excuse to be stupid." The practices of XP, including TDD, are done because they've been found to be useful. They're not carved in stone. If you find something useful, then use it. Mark
  12. I disagree with the latter half of your assertion. Tests (unit or otherwise) typically provide an input and expect an output or a failure. Private methods are always invoked from publically accessible interfaces and are therefore indirectly in the code-path of a test. A good design should not need to test any private methods explicitly. As a corollary, a test for a private method is always an indication of an opportunity for refactoring your code.