drupsys/codeception-use-cases-module

支持基于用例测试的Codeception模块

2.0.7 2023-11-02 18:40 UTC

README

这是一个用于基于用例测试的codeception模块,该模块旨在推广编写真实的单元测试,如Ian Cooper在“TDD,Where Did It All Go Wrong”演讲中所描述的。

相关参考

设置

假设您有tests/usecase.suite.yaml文件,可以通过以下方式启用此模块:

actor: UseCaseTester
modules:
    enabled:
        - \Helper\UseCase
        - \MVF\Codeception\UseCases\Module:
            providers:
                mysql: App\Providers\UseCases\EloquentProvider
                redis: App\Providers\UseCases\RedisProvider
        - Asserts

特别注意的是,将\MVF\Codeception\UseCases\Module添加到模块列表中。此模块需要配置才能正确运行,必须定义providers列表。

MySql Provider

这是一个必须实现MVF\Codeception\UseCases\Contracts\MySqlInterface的对象,其外观可能如下所示。

namespace App\Providers\UseCases;

use Illuminate\Database\Connection;
use MVF\Codeception\UseCases\Contracts\MySqlInterface;

class EloquentProvider implements MySqlInterface
{
    public function __construct() {}

    public function getMySql(): Connection
    {
        return ...; // return writable eloquent connection, this connection should be privileged, able to write, read, delete and truncate tables. 
    }
}

Redis Provider

这是一个必须实现MVF\Codeception\UseCases\Contracts\RedisInterface的对象,其外观可能如下所示。

namespace App\Providers\UseCases;

use MVF\Codeception\UseCases\Contracts\RedisInterface;
use Redis;

class RedisProvider implements RedisInterface
{
    public function __construct() {}

    public function getRedis(): Redis
    {
        return ...; // return redis object
    }
}

服务

您的docker compose文件应包含以下服务:

  <app>-test-mysql:
    container_name: <app>-test-mysql
    networks: [mvf_shared]
    image: mysql:5.7.26
    environment:
      MYSQL_ROOT_PASSWORD: 12345
      MYSQL_DATABASE: ...
      MYSQL_USER: ...
      MYSQL_PASSWORD: ...
    healthcheck:
      test: mysqladmin -uroot -p12345 ping -h localhost
      interval: 2s
      timeout: 20s
      retries: 10
    volumes:
      - mysql-test:/var/lib/mysql:cached
    command: --server-id=1 --log-bin=test.log

  <app>-binlog-parser:
    build:
      context: build/binlog-parser
    container_name: <app>-binlog-parser
    networks: [mvf_shared]
    restart: always

  <app>-redis:
    container_name: <app>-redis
    networks: [mvf_shared]
    image: redis:6-alpine

  networks:
    mvf_shared:
      external: true

<app>-test-mysql

MySql服务应将MYSQL_ROOT_PASSWORD设置为12345,具有以下标志的命令:--server-id=1 --log-bin=test.log,如果您已经定义了某些命令,只需将此标志附加到现有命令,并且应使用[mvf_shared]网络。

<app>-binlog-parser

Maxwell服务也应使用[mvf_shared]网络,并且应在build/binlog-parser文件夹中构建。此文件夹应包含Dockerfileconfig.properties文件。

以下是你Dockerfile的内容,检查maxwellalpine版本以查看是否有更新的版本可用。

FROM openjdk:18-ea-11-jdk-alpine3.15

RUN apk add --no-cache --update bash shadow
RUN /usr/sbin/groupadd -g 1000 www
RUN /usr/sbin/useradd -s /bin/sh -g 1000 -u 1000 www

ENV MAXWELL_VERSION=1.35.5

COPY --from=zendesk/maxwell:v1.35.5 /app /app

WORKDIR /app

RUN chown 1000:1000 /app && echo "$MAXWELL_VERSION" > /REVISION

USER 1000

COPY config.properties ./config.properties

CMD [ "/bin/bash", "-c", "bin/maxwell", "--config=/app/config.properties" ]

以下是你config.properties的内容。

log_level=info

# mysql source config
host=<app>-test-mysql
user=root
password=12345

# redis target config
producer=redis
redis_key=maxwell
redis_type=xadd
redis_host=<app>-redis
redis_port=6379

此配置的大部分内容应该很直观,唯一需要说明的是redis_key,这是Maxwell将所有bin日志数据存储的位置,默认情况下此键设置为maxwell,但如果您已经在应用程序中使用此键,则需要更改其值。

如果您将redis_key的值更改为testing,则还必须在测试套件中提供额外的配置。假设您有tests/usecase.suite.yaml,则新的redis_key也必须在此处定义,如下所示。

actor: UseCaseTester
modules:
    enabled:
        - \MVF\Codeception\UseCases\Module:
            providers: ...
            redis_key: testing # <- this needs to match redis key in config.properties

<app>-redis

Redis服务应像其他服务一样使用[mvf_shared]网络。

需求和动机

为此模块正常工作,您将需要以下内容:

  • 启用binlog的MySql测试数据库
  • Maxwell守护进程读取binlog并将它们推送到Redis
  • Redis缓存以存储binlog数据

此模块中有很多内容,我假设您会有很多问题,让我们先回答一些问题。

为什么我们需要启用binlog的mysql测试服务器?

简短的答案是,这是Maxwell守护进程了解数据库上执行了哪些变更所必需的。

什么是Maxwell守护进程?

这是一个消耗mysql binlog、将它们转换为简单的json对象并将它们发送到支持的目标之一的过程,在我们的案例中是一个Redis服务器。

为什么此模块需要Redis才能运行?

再次回答,简单地说,Maxwell 守护进程使用 Redis 作为 binlog 的存储。有许多不同的服务可以作为 Maxwell 守护进程存储 binlog 的位置,但 Redis 是最合适的,因为我们需要在 PHP 代码中读取存储的数据,从 Redis 中读取数据非常简单。

这一切的意义是什么?

增加的复杂性解决了我们与数据库重置相关的问题。我们正在使用的数据库在每次测试后大约需要 40 秒才能重置。Maxwell 守护进程使我们能够知道哪些表受到了影响,因此我们可以只截断必须截断的表。这提高了每次测试的速度大约 120 倍。

这也为我们提供了一种编写纯声明性测试的方法,在你的测试过程中任何时候都不需要与数据库交互或编写逻辑。编写测试的过程可以用以下步骤来概括

  • 声明应用程序的 初始状态
  • 运行待测试的代码
  • 声明对应用程序的 最终状态 的断言

初始状态 只是一个关联数组,描述了代码执行之前应用程序的状态,而 最终状态 是一个关联数组,描述了代码执行之后应用程序的状态。