在PHPUnit中模拟Symfony2的请求和会话

Tek*_*Tek 10 service phpunit mocking symfony

我有需要的一类Symfony2服务@request_stack返回的一个实例Symfony\Component\HttpFoundation\RequestStack.我用它来检索POST和GET值.

也是我的类使用Symfony\Component\HttpFoundation\SessionRequest->getSession()它调用来获得当前会话.

现在我的类有一个看起来像这样的方法:

class MyClass {
    public function doSomething() {
        //Get request from request stack.
        $Request = $this->RequestStack->getCurrentRequest();

        //Get a variable from request
        $var = $Request->request->get('something');
        //Processes $var into $someprocessedvar and lets say it's equal to 3.
        //Set value to session.
        $this->Request->getSession()->set('somevar', $someprocessedvar);
    }
}
Run Code Online (Sandbox Code Playgroud)

我需要能够:

  1. 模拟RequestStack.
  2. 获得RequestRequestStack
  3. 获得SessionReques吨;

尽管如此,我如何测试MyClass成功设置会话中的预期值?

Kev*_*her 9

并非所有代码都值得单元测试.通常这表明您的代码可以简化.当您对单个测试代码进行单元测试时,测试可能会成为一种负担,通常情况下,在这些情况下进行边对边测试的集成会更好.在你的例子中也不清楚你的类是如何得到的RequestStack所以我会假设它已被注入__construct.

这就是说你将如何测试该代码:

protected function setUp()
{
    $this->requestStack = $this->getMock('Fully-qualified RequestStack namespace');

    $this->SUT = new MyClass($this->requestStack);
}    

/** @test */
public function it_should_store_value_in_the_session()
{
    $value = 'test value';

    $request = $this->getMock('Request');
    $request->request = $this->getMock('ParameterBag');
    $session = $this->getMock('Session');

    $this->requestStack
        ->expects($this->atLeastOnce())
        ->method('getCurrentRequest')
        ->will($this->returnValue());

    $request->request
        ->expects($this->atLeastOnce())
        ->method('get')
        ->with('something')
        ->will($this->returnValue($value));

    $request
        ->expects($this->once())
        ->method('getSession')
        ->will($this->returnValue($session));

    $session
        ->expects($this->once())
        ->method('set')
        ->with('somevar', $value);

    $this->SUT->doSomething();
}
Run Code Online (Sandbox Code Playgroud)

这应该给你一个起点,但要注意你的测试中有一堆模拟,因为实现细节的微小变化会导致你的测试失败,即使行为仍然是正确的,这是你想要避免的事情.可能因此测试维护成本不高.

编辑:我想到了更多关于你的问题,并意识到通常你可以将Session作为依赖注入.如果在您的用例中可以实现,那么它将大大简化测试.


thi*_*ini 5

您无需嘲笑RequestStack,这是一个非常简单的类。您可以创建一个虚假请求并将其推送到该请求。您也可以模拟会话。

// you can overwrite any value you want through the constructor if you need more control
$fakeRequest = Request::create('/', 'GET');

$fakeRequest->setSession(new Session(new MockArraySessionStorage()));
$requestStack = new RequestStack();
$requestStack->push($fakeRequest);
// then pass the requestStack to your service under test.
Run Code Online (Sandbox Code Playgroud)

但是就测试而言,必须弄乱类的内部不是一个好兆头。也许您可以创建一个处理程序类来封装请求栈中所需的逻辑,以便您可以更轻松地进行测试。