Regarding Karl Manaster’s exact answer, there are some flaws that you should at least consider before embarking on the path suggested by Karl.
The most significant of these is the following: we use encapsulation to minimize the number of potential dependencies that carry the greatest likelihood of changes propagating. In your case, you have encapsulated private methods inside your class: they are not available for other classes and, therefore, there are no potential dependencies on them: the cost of any changes you make to them is minimized and has a low probability of propagating to other classes.
It seems that Karl suggests moving some private methods from your class to a new class and making these methods public (so you can test them). (By the way, why not just make them public in the original class?)
Thus, you remove the barrier to dependencies of other classes, forming dependencies on these methods, which will potentially increase the cost of tracking these methods if any other class takes them to use.
You can judge this small secondary and worthwhile price to pay for the opportunity to test your personal methods, but at least know about it. In a small number of cases, this can really be useful, but if you implement it in your entire code base, you will sharply increase the likelihood that these dependencies will form, increasing the cost of your service cycle to an unknown degree.
For these reasons, I disagree with Karl that his suggestion is: "... a great example of how TDD improves your design."
In addition, he states: "In the original class, this extraneous functionality disappeared, wrapped in a sprouted class, so the design of the original class is simpler and better in line with the principle of shared responsibility."
I would say that roaming functionality is not at all "external." In addition, "Simpler" is not clearly defined: of course, it may be that the simplicity of a class is inversely proportional to its size, but this does not mean that the system of the simplest possible classes will be the simplest possible system: if in this case all classes will contain only one method, and the system will have a huge number of classes; removing this hierarchical layer from several methods within classes, one could argue, would make the system much more complicated.
The principle of single responsibility (SRP), in addition, is, as you know, subjective and completely depends on the level of abstraction of the observer. Not at all that removing a method from a class automatically improves its SRP compliance. A printer class with 10 methods has sole responsibility for printing at the class abstraction level. One of its methods may be checkPrinterConnected (), and may be checkPaper (); at the method level, these are clearly separate responsibilities, but they do not automatically assume that the class should be split into other classes.
Carl concludes: "In the sprouted class, the extracted functionality is raison d'etre, so it should be publicly available, and therefore it can be tested without modifications for testing purposes only." The value of functionality (this is raison-detre-ness) is not a basis for the relevance of its publicity. The basis for the acceptability of public functionality is to minimize the interface open to the client, so that the functionality of the class is available for use, while the independence of the client from the implementation of the functionality is maximized. Of course, if you only move one method to a sprouted class, then it should be publicly available. However, if you are moving multiple methods, you must make these methods publicly available, which is important for a client to successfully use the class: these public methods can be much less important than some private methods from which you want to protect your client. (In any case, I am not a fan of this, "Raison-d'etre", the phrase as the importance of the method is also not defined.)
An alternative approach to Karl suggests that it depends on how big your system is for growth. If it grows to less than a few thousand classes, you might think of a script copying the source code to a new directory, changing all the events, "private" to, "public" in that copied source, and then write your tests against the copied source . This has the lack of time required to copy the code, but the advantage of preserving the encapsulation of the original source, but all methods are checked in the copied version.
Below is the script used for this purpose.
Hi,
Ed kirvan
! / Bin / bash
rm -rf code-copy
echo Creating a copy code ...
mkdir code-copy
cp -r ../ www code-copy /
for I'm in find code-copy -name "*php" -follow ; to do
sed -i 's/private/public/g' $i
to do
php run_tests.php