vendredi 13 octobre 2017

Testing class with high cohesion but reasonably complex logic

For example, I have a class that takes raw data, analyses it and returns numbers for a report. Let's call it SomeReportDataProvider

class SomeReportDataProvider
{
    public function report(array $data)
    {
        $data = $this->prepare($data);

        $report = [];
        foreach ($data as $item) {
            if ($row->somefield == 'somevalue') {
                $report = $this->doThis($report, $row);
            } else {
                $report = $this->doThat($report, $row);
            }
        }

        // ... do something else

        $report = $this->postProcess($report);

        return $report;
    }

    protected function doThis($item)
    {
        // ... do some math, probably call some other methods
    }

    protected function doThat($item)
    {
        // ... do other math
    }

    // ... and so on
}

So the class really does only one thing, step-by-step proccessing of raw data for some report. It's not big, most likely 4-6 methods with 5-10 lines. All of its methods are tightly related and serve one purpose, so I would say that it has high cohesion. But what's the best way to test the class?

If I try to approach it with mentality "test behavior, not implementation", I should test only it's single public method. The advantage of this approach is that it's easy to refactor the class later without even touching the tests, and I would be sure that it still exibits exactly same behavior. But it's also can be really hard to cover all cases through single method, too many possible code paths.

I can make most (probably all) methods public and test them in isolation, but then I'm breaking encapsulation of class and algorithm and testing implementation details of it. Any refactoring would be harder and unwanted changes in behavior more likely.

As a last option, I can break it into small classes, most likely having 1 or 2 methods. But is it really a good idea to break higly cohesive class into smaller, tightly coupled classes, that do very specific thing and aren't reused anywhere else? Also it's still will be more difficult to refactor. And probably harder for other developers to quickly get a full picture of how it works.

Aucun commentaire:

Enregistrer un commentaire