dbstudios/analyst

受GitHub的Scientist启发的功能测试库

2.0.1 2016-01-27 22:41 UTC

This package is auto-updated.

Last update: 2024-09-19 09:40:51 UTC


README

Build Status Coverage Status

Latest Stable Version Total Downloads License

Analyst

一个受GitHub的Scientist启发的PHP功能测试库。

请注意,这个README是一个正在进行中的工作,可能包含不完整的信息。

安装

$ composer require dbstudios/analyst

我该如何分析?

让我们假设你有一个大型网络应用,你正在改变验证用户访问页面权限的方式。

class MyController {
    public function isAllowed(User $user, $slug) {
        return Experiment::create('user-allowed')
            ->setContext([
                'user' => $user, // context ignores keys, however it's helpful to use keys to "flag" what each variable means
                'slug' => $slug,
            ])
            ->control(function(User $user, $slug) {
                return $user->isAdmin() || $user->getPermissions()->contains('view.page.' . $slug);
            })
            ->candidate(function(User $user, $slug) {
                return $user->getPermissionProvider()->isAccessAllowed($slug);
            })
            ->run();
    }
}

就是这样!Experiment类的run方法将始终返回你的控制结果。你的控制和候选者都将运行,Analyst将记录这两段代码发生的情况。在下一节中,我们将看看你可以如何使用这些信息。

发布实验结果

如果我们不对从实验中获得的信息进行处理,测试多个代码路径就毫无意义。这就是发布发挥作用的地方。你所要做的就是在一个自定义的Experiment类中实现那个publish方法。

class MyExperiment extends Experiment {
    private $db;
    private $stmt;

    public function __construct(PDO $db, $name = 'experiment') {
        parent::__construct($name);
        
        $this->db = $db;
        $this->stmt = $db->prepare('insert into experiment_results (name, timestamp, behavior, is_control,
            execution_time, result) values(:experiment, UTC_TIMESTAMP(), :behavior, :control, :duration, :result)');

        $this->stmt->bindValue(':experiment', $name);
    }

    public function publish(Result $result) {
        $behaviors = $result->getCandidates();
        
        array_unshift($candidates, $result->getControl());
        
        $this->db->beginTransaction();
        
        foreach ($behaviors as $behavior) {
            $this->stmt->bindValue(':behavior', $behavior->getName());
            $this->stmt->bindValue(':control', $behavior === $result->getControl(), PDO::PARAM_BOOL);
            $this->stmt->bindValue(':duration', $behavior->getDuration());
            $this->stmt->bindValue(':result', serialize($behavior->getResult());
            
            $this->stmt->execute();
        }
        
        $this->db->commit();
    }
    
    public static function create($db, $name = 'experiment') {
        return new MyExperiment($db, $name);
    }
}

现在,如果我们把之前关于用户权限的例子重写为使用我们的自定义MyExperiment类,它看起来会是这样。

class MyController {
    public function isAllowed(User $user, $slug) {
        return MyExperiment::create($this->getConnection(), 'user-allowed')
            // set up context, control, and candidate...
            ->run();
    }
}

在上面的例子中,我们创建了自己的Experiment实现,命名为MyExperiment。我们确保我们有一个数据库连接(使用PHP的PDO类),并使用publish方法将数据写入其中。然后,当我们在我们控制器示例中运行实验时,我们只需要向MyExperimentcreate静态方法提供额外的参数(这是我们自行实现的,以便允许额外的构造函数参数)。

每次实验运行完毕后,Analyst都会始终调用用于分析所使用的实验的publish方法。我们的选项不仅限于简单的数据库插入。你可能会决定使用像Monolog这样的库将数据记录到文件中,或者你可能将其发送到云服务。这取决于你!