0

我在理解单元测试方面取得了一些进展,但是对于我尝试测试的每一种方法,都有新的问题:

public function handle( SendNotification $command ) {

    $DTO = $this->Assembler->build();

    $subject = sprintf(
        $command->getFirstName(),
        $command->getLastName()
    );

    $EmailComponents = new EmailComponents(
        $subject,
        $DTO->getProject()->getSettings()->getValueOf( 'recipient' ),
        $this->OptionQuery->getOption( 'business_email' ),
        $this->NotificationRenderFactory->render( 'template' ) )
    );

    $this->Mailer->send( $EmailComponents );

}

$DTO基本上是一个聚合集群,“项目”是聚合根。它从 PHP Session 中读取数据以确定当前项目,并OptionQuery从数据库中读取数据。所以我目前的理解是,我必须创建一个夹具来设置一个聚合、一个测试数据库和一个为我的会话对象返回某些内容的模拟。这是正确的,如果是这样,我为什么要花这么多精力来测试一种方法?

编辑同时,我重构了该handle方法以使其更具可测试性:

public function handle( SendNotification $command ) {

    $EmailComponents = $this->EmailComponentsAssembler->build( $command );

    $this->Mailer->setup( $EmailComponents );

    $this->Mailer->send();

}

汇编器的build方法(实际上更像是一个工厂)仍然很丑陋:

public function build( SendNotification $command ): EmailComponentsDTO {

    $request = Request::createFromGlobals();

    $Recipient = $this->ProjectRecipientEmailQuery->execute( $request->request->get( 'destination' ) );

    if ( !\is_email( $Recipient ) ) :

        throw new \Exception( 'No email address found!' );

    endif;

    return new EmailComponentsDTO(
        TRUE,
        $Recipient,
        (array)$command->getCustomField( 'additional_recipients' ),
        $this->OptionQuery->getOption( 'email_from' ),
        $this->OptionQuery->getOption( 'email_email' ),
        (string)$this->NotificationSubject->render( $command ),
        (string)$this->NotificationRenderFactory->render( 'EmailNotification', $command ),
        $command->getPriority()
    );
}

但我觉得现在的担忧已经分开了一点。

4

1 回答 1

2

单元测试是为了在孤立的代码中发现错误。但是您的代码主要是交互,例如与Assembler,MailerEmailComponents。这部分代码中的错误将在于与其他软件部分的交互:您是否以正确的顺序调用正确的函数并使用正确的参数与具有正确内容的论点的顺序?使用 mock 进行测试不会回答您这些问题:如果您误解了如何调用库,那么您实现的 mock 将反映您自己的误解。相反,您应该使用集成测试来测试此类代码。

那里唯一的算法代码是:

$subject = sprintf(
    $command->getFirstName(),
    $command->getLastName()
);

这在我看来甚至是错误的,因为我希望某些格式字符串是第一个参数sprintf(但我不熟悉 php)。如果我认为这是一个错误是正确的,那么严格来说,它也是一个集成错误,但是您可以通过单元测试找到它,因为您不会费心 stub sprintf

因此,您的测试问题的一个可能解决方案是将主题字符串的创建提取到一个小的帮助函数中,并使用单元测试对其进行测试,但使用集成测试测试其余功能。

于 2019-02-04T23:16:12.450 回答