There are a couple of good reasons not to use recursion, but this is not a reason not to use recursion at all. Programs, first, are created by programmers for programmers, and only secondly, by programmers for computers. In the end, some suitable programs can be used by untrained people. Recursion has one unconditional advantage over iteration - readability. When a programmer creates programs for his own kind, the recursion has the right to exist until it proves the opposite (i.e., it is not running on the computer and does not choke with real data).
Testing is, in essence, the creation of programs for programs that allow programmers to push back the threshold of insurmountable complexity in developed applications. Faced with the need to write a unit test for the recursive method, I was unpleasantly surprised by the need to mock the test method itself. The alternative is to create such input data that would allow testing all branches of recursion in a single test method. In the future, it was not a decrease in complexity that was looming, but, on the contrary, an increase in complexity. Having rummaged through the Internet, I discovered a lot of information about what recursion is not good for, a lot of advice on how to move from recursion to iteration, but I could not find what I was looking for in Russian forms - how to test the recursive method. Deciding that preparing test data for three passes through the code is not such an insurmountable difficulty, I postponed this task until the morning. Under the cut, the solution that came to mind for the night, allowing to break the testing of recursive methods into parts.
public function foo($arg1, $arg2) { //... $out = $this->foo($in1, $in2); //... }
Create a wrapper for the method and make it so that the method itself calls only the wrapper, and the wrapper calls the method:
public function foo($arg1, $arg2) { //... $out = $this->fooRecursive($in1, $in2); //... } public function fooRecursive($arg1, $arg2) { return $this->foo($arg1, $arg2); }
public function test_foo() { /* create mock for wrapper 'fooRecursive'*/ $obj = \Mockery::mock(\FooClass::class . '[fooRecursive]'); $obj->shouldReceive('fooRecursive')->once() ->andReturn('out'); /* call recursive method 'foo' */ $res = $obj->foo('arg1', 'arg2'); }
Yes, the decision is very straightforward, but maybe someone will come in handy, and he will manage to spend his night on something more useful.
Source: https://habr.com/ru/post/307640/
All Articles