【问题标题】:Is this Command Handler testable?这个命令处理程序是可测试的吗?
【发布时间】:2019-05-09 10:45:27
【问题描述】:

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

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()
    );
}

但我觉得现在的顾虑稍微好一些了。

【问题讨论】:

    标签: php database unit-testing session fixtures


    【解决方案1】:

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

    里面唯一的算法代码是:

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

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

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

    【讨论】:

    • 感谢您查看我的代码。我已经对其进行了重构,使其更具可测试性并希望更有意义(请参阅原始问题的编辑)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-09
    • 2016-09-04
    • 2021-11-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多