PHP单元测试-使用功能实例在其中测试功能

问题描述 投票:0回答:1

我正在学习测试的技巧,需要您的一些帮助。我有一个功能(旧版代码)需要测试,该功能接收一些数据作为参数,将其暂时保存在数据库中并发送到外部API。如果api响应为200,则更新表中的数据以明确保留该数据,否则将其删除。

这是代码:

public function sendAssignments(Challenge $challenge, int $reportType)
{
    $reportModel      = new Report($challenge, $reportType);
    $pointsList       = $this->calculateAssignments($challenge, $reportType);
    $pharmsToSend     = $pointsList['pharmsCollection'];
    $pointsArray      = $pointsList['pointsArray'];

    $savedAt          = Date('Y-m-d H:i:s');
    $symfonyService   = new SymfonyService();
    $requestUid       = \uniqid('AS-', false);

    $sentAt           = Date('Y-m-d H:i:s');
    $reportModel->persistReportAssignments($pharmsToSend, $savedAt, $sentAt, false);
    $symfonyResult    = $symfonyService->sendReportPoints(
        $requestUid, 
        $challenge->challenge_id, 
        $pointsArray
    );

    if ($symfonyResult->code == "200") {
        // Actualizamos los datos
        $reportModel->persistReportAssignments($pharmsToSend, $savedAt, $sentAt, true);
        FlashMessage::addSuccess('Se han asignado los puntos del reporte.', 'Asignación correcta');
    } else {
        $reportModel->deleteFailedAssignmentsFromDatabase($savedAt);
        FlashMessage::addError($symfonyResult->msg, 'Error '.$symfonyResult->code.' - No se han asignado los puntos');
    }

    if ($reportType == Report::REPORT_CONNECTED) {
        return redirect()->route('reports.showConnectedReport', ['challenge'=>$challenge]);
    } else if ($reportType == Report::REPORT_MANUAL) {
        return redirect()->route('reports.showManualReport', ['challenge'=>$challenge]);
    }
}

我正在测试功能,而不是API调用,所以我想模拟SymfonyService类,为此,我编写了一个新类:

class SymfonyServiceMock
{
    public function sendReportPoints()
    {
        return ["operation"=>"ok", "code" => 200];
    }
}

但是问题是SymfonyService正在功能内部实例化,所以我不能使用SymfonyServiceMock类来模拟API调用。这是我的疑问,我是否必须重构该功能才能将SymfonyService传递给它?这是正确的方法吗?

我的意思是这样的重构:

public function sendAssignments(Challenge $challenge, int $reportType, SymfonyService $symfonyService)
{
    // The rest of the code here, but without instantiating SymfonyService
}

如果您有另一个更好的方法来测试它(最好遵循SOLID原理),我将很高兴知道。

非常感谢

编辑:我有这个想法,我已经在AppServiceContainer上注册了SymfonyService,现在我在控制器上注入了SymfonyService,这样我就可以像这样重构:

public function sendAssignments(Challenge $challenge, int $reportType)
{
    $this->executeSendAssignmentsOperation($challenge, $reportType);

    if ($reportType == Report::REPORT_CONNECTED) {
        return redirect()->route('reports.showConnectedReport', ['challenge'=>$challenge]);
    } else if ($reportType == Report::REPORT_MANUAL) {
        return redirect()->route('reports.showManualReport', ['challenge'=>$challenge]);
    }
}

public function executeSendAssignmentsOperation(Challenge $challenge, int $reportType)
{
    $reportModel      = new Report($challenge, $reportType);
    $pointsList       = $this->calculateAssignments($challenge, $reportType);
    $pharmsToSend     = $pointsList['pharmsCollection'];
    $pointsArray      = $pointsList['pointsArray'];

    $savedAt          = Date('Y-m-d H:i:s');
    $sentAt           = Date('Y-m-d H:i:s');

    $reportModel->persistReportAssignments($pharmsToSend, $savedAt, $sentAt, false);
    $symfonyResult    = $this->_symfonyService->sendReportPoints(
        $challenge, 
        $pointsArray,
        $reportType
    );

    $sentAt           = Date('Y-m-d H:i:s');

    if ($symfonyResult->code == "200") {
        // Actualizamos los datos
        $reportModel->persistReportAssignments($pharmsToSend, $savedAt, $sentAt, true);
        FlashMessage::addSuccess('Se han asignado los puntos del reporte.', 'Asignación correcta');
    } else {
        $reportModel->deleteFailedAssignmentsFromDatabase($savedAt);
        FlashMessage::addError($symfonyResult->msg, 'Error '.$symfonyResult->code.' - No se han asignado los puntos');
    }
}

现在有了这个重构,我可以编写测试了。但是,我仍然想知道这是否是解决问题的正确方法。如果没有,请您解释一下原因?

php phpunit
1个回答
0
投票

PhpUnit也有同样的问题。无法模拟在被测系统中创建的类。

唯一对我有用的解决方案是使用Kahlan(https://github.com/kahlan/kahlan)测试代码,该代码可以动态模拟类。但是它要求通过composer将类自动加载为类。

也许这会有所帮助:)

热门问题
推荐问题
最新问题