我有一个类需要Symfony2
服务@request_stack
,它返回Symfony\Component\HttpFoundation\RequestStack
的实例。我用它来检索POST和GET值。
此外,我的班级使用来自Symfony\Component\HttpFoundation\Session
的{{1}}来调用当前会话。
现在我的班级有一个看起来像这样的方法:
Request->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);
}
}
。RequestStack
Request
RequestStack
t; Session
醇>
所有这些说明如何测试Reques
是否成功设置了会话中的预期值?
答案 0 :(得分:8)
并非所有代码都值得单元测试。通常这表明您的代码可以简化。当您对单个测试代码进行单元测试时,测试可能会成为一种负担,通常情况下,在这些情况下进行边对边测试的集成会更好。在您的示例中,您的班级如何获得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();
}
这应该给你一个起点,但要注意你的测试中有一堆模拟,因为实现细节的微小变化会导致你的测试失败,即使行为仍然是正确的,这是你想要避免的尽可能保持测试的成本并不高。
编辑:我想到了更多关于你的问题,并意识到通常你可以将Session作为依赖注入。如果在您的使用案例中可以实现,则会大大简化测试。
答案 1 :(得分:4)
你不需要模拟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.
但是在测试方面,不得不乱用一个类的内部并不是一个好兆头。也许您可以创建一个处理程序类来封装您需要的逻辑,以便您可以更轻松地进行测试。
答案 2 :(得分:3)
很难想象你必须在单元测试的类中处理GET / POST参数的情况。让Controller处理HTTP请求和会话(这几乎就是它们的用途),并将变量传递给相关的类来处理其余的。
话虽如此,凯文的回答是一个可能的解决方案,如果你想沿着这条路走下去。
答案 3 :(得分:0)
我开始做以下工作:
public function testCompanySession()
{
$Request = new Request();
$Request->setSession(
new Session(new MockArraySessionStorage())
);
$CompanySessionMapper = new CompanyMapper($Request);
$Company = new Company();
$Company->setName('test');
$CompanySessionMapper->set($Company);
$Company = new Company();
$CompanySessionMapper->get($Company);
$this->assertEquals($Company->getName(), 'test');
}
在我的情况下,每个对象类型只有一个测试,因为我只测试会话名称是否正确并在会话中正确检索/存储对象。 CompanyMapper
类使用会话将公司对象存储在其他与会话/应用程序相关的函数中。
答案 4 :(得分:0)
像我这样来自谷歌的任何人都想知道如何模拟请求内容,它就像:
use AppBundle\Controller\DefaultController;
use Symfony\Component\HttpFoundation\Request;
use PHPUnit\Framework\TestCase;
class DefaultControllerTest extends TestCase
{
//@dataProvider?
public function testWithMockedRequest()
{
//create a request mock
$request = $this
->getMockBuilder(Request::class)
->getMock();
//set the return value
$request
->expects($this->once())
->method('getContent')
->will($this->returnValue('put your request data here'));
//create your controller
$controller = new DefaultController();
//get the Response based on your Request
$response = $controller->myRequestAction($request);
//assert!
$this->assertEquals(200, $response->getStatusCode());
}
}
如您所见,您可以执行使用$request->getContent()
我希望这有助于某人。