我目前正在使用Symfony2,我正在使用PHPUnit测试我的项目。 我想在使用错误参数提交表单或URL未完成时测试异常。
我通过了Symfony2和PHPUnit的文档,但没有找到任何类/方法。
如何更改表单操作的值?我想使用PHPUnit,因此创建的报告是最新的,我可以看到我的代码的覆盖范围。
修改
澄清我的问题,一些新的内容。
如何测试以'>'开头的行在我的控制器? (throw $this->createNotFoundException('Unable to find ParkingZone entity.');
)
当用户修改操作链接时,在控制器中,进程将通过异常(或错误消息,如果选择此操作)。我该如何测试这个案例?
控制器
/**
* Edits an existing ParkingZone entity.
*
* @Route("/{id}/update", name="parkingzone_update")
* @Method("post")
* @Template("RatpGarageL1Bundle:ParkingZone:edit.html.twig")
*/
public function updateAction($id)
{
$em = $this->getDoctrine()->getEntityManager();
$entity = $em->getRepository('RatpGarageL1Bundle:ParkingZone')->find($id);
if (!$entity) {
> throw $this->createNotFoundException('Unable to find ParkingZone entity.');
}
$editForm = $this->createForm(new ParkingZoneType(), $entity);
$deleteForm = $this->createDeleteForm($id);
$request = $this->getRequest();
$editForm->bindRequest($request);
if ($editForm->isValid()) {
$em->persist($entity);
$em->flush();
return $this->redirect($this->generateUrl('parkingzone_edit', array('id' => $id)));
}
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
查看:
<form action="{{ path('parkingzone_update', { 'id': entity.id }) }}" method="post" {{ form_enctype(form) }}>
<div class="control-group">
{{ form_label(form.name, 'Name', { 'attr': {'class': 'control-label'} } ) }}
<div class="controls error">
{{ form_widget(form.name, { 'attr': {'class': ''} } ) }}
<span class="help-inline">{{ form_errors(form.name) }}</span>
</div>
</div>
<div class="control-group">
{{ form_label(form.orderSequence, 'Rang', { 'attr': {'class': 'control-label'} } ) }}
<div class="controls error">
{{ form_widget(form.orderSequence, { 'attr': {'class': ''} } ) }}
<span class="help-inline">{{ form_errors(form.orderSequence) }}</span>
</div>
</div>
<div class="control-group">
{{ form_label(form.image, 'Image', { 'attr': {'class': 'control-label'} } ) }}
<div class="controls error">
{{ form_widget(form.image, { 'attr': {'class': ''} } ) }}
<span class="help-inline">{{ form_errors(form.image) }}</span>
</div>
</div>
{{ form_rest(form) }}
<div class="form-actions">
<button type="submit" class="btn btn-primary">Enregistrer</button>
<a href="{{ path('parkingzone') }}" class="btn">Annuler</a>
</div>
</form>
答案 0 :(得分:2)
Symfony本身没有任何对象可以通过它来操作表单的动作,因为它在html(twig文件)中设置。但是,twig提供了动态更改twig文件中表单操作的功能。
基本方法是控制器通过渲染调用将参数传递到twig文件中。然后twig文件可以使用此参数动态设置表单操作。如果控制器使用会话变量来确定此参数的值,那么通过在测试程序中设置此会话变量的值,可以专门为测试设置表单操作。
例如在控制器中:
public function indexAction()
{
$session = $this->get('session');
$formAction = $session->get('formAction');
if (empty($formAction)) $formAction = '/my/normal/route';
...
return $this->render('MyBundle:XXX:index.html.twig', array(
'form' => $form->createView(), 'formAction' => $formAction)
);
}
然后,在twig文件中:
<form id="myForm" name="myForm" action="{{ formAction }}" method="post">
...
</form>
然后,在测试程序中:
$client = static::createClient();
$session = $client->getContainer()->get('session');
$session->set('formAction', '/test/route');
$session->save();
// do the test
这不是唯一的方法,有各种可能性。例如,会话变量可以是$ testMode,如果设置了此变量,则表单将$ testMode = true传递给render调用。然后twig文件可以将表单操作设置为两个值之一,具体取决于testMode变量的值。
答案 1 :(得分:1)
Symfony2区分了各个类的单元测试和应用程序行为的功能测试。通过直接实例化类并在其上调用方法来执行单元测试。通过模拟请求和测试响应来执行功能测试。有关详细信息,请参阅symfony testing。
表单提交只能在功能上进行测试,因为它由Symfony控制器处理,该控制器始终在容器的上下文中运行。 Symfony功能测试必须扩展WebTestCase类。此类提供对客户端的访问,该客户端用于请求URL,单击链接,选择按钮和提交表单。这些操作返回表示HTML响应的爬网程序实例,该响应用于验证响应是否包含预期内容。
测试在执行单元测试时抛出异常是恰当的,因为功能测试涵盖了与用户的交互。用户永远不应该意识到抛出了异常。因此,最糟糕的情况是异常被Symfony捕获,并且在生产中向用户呈现全部响应“哎呀,发生了错误”(或类似的定制消息)。但是,这应该只在应用程序损坏时发生,而不是因为用户错误地使用了应用程序。因此,在功能测试中通常不会测试它。
关于问题中提到的第一个场景 - 提交带有错误参数的表单。在这种情况下,应向用户显示一条错误消息,告诉他们输入有什么问题。理想情况下,控制器不应抛出异常,但应使用symfony validation根据需要自动生成每个字段旁边的错误消息。无论错误如何显示,都可以通过检查提交表单的响应是否包含预期错误来测试。例如:
class MyControllerTest extends WebTestCase
{
public function testCreateUserValidation()
{
$client = static::createClient();
$crawler = $client->request('GET', '/new-user');
$form = $crawler->selectButton('submit')->form();
$crawler = $client->submit($form, array('name' => '', 'email' => 'xxx'));
$this->assertTrue($crawler->filter('html:contains("Name must not be blank")')->count() > 0,
"Page contains 'Name must not be blank'");
$this->assertTrue($crawler->filter('html:contains("Invalid email address")')->count() > 0,
"Page contains 'Invalid email address'");
}
}
关于第二种情况 - URL未完成。使用Symfony时,任何与定义的路由不匹配的URL都将导致NotFoundHttpException。在开发中,这将导致诸如“找不到”GET / xxx“的路由”之类的消息。在生产中,它将导致全部“哎呀,发生错误”。可以在开发中测试响应包含“找不到路由”。然而,在实践中,测试它并没有多大意义,因为它是由Symfony框架处理的,因此是给定的。
编辑:
关于URL包含标识对象的无效数据的情况。这可以在单元测试程序中进行测试(开发中):
$client = static::createClient();
$page = $client->request('GET', '/update/XXX');
$exceptionThrown = ($page->filter('html:contains("NotFoundException")')->count() > 0) && ($page->filter('html:contains("Unable to find ParkingZone entity")')->count() > 0);
$this->assertTrue($exceptionThrown, "Exception thrown 'Unable to find ParkingZone entity'");
如果您只想测试抛出异常而不是特定类型/消息,您只需过滤html中的'Exception'即可。请记住,在生产中,用户只会看到“糟糕,发生了错误”,“异常”一词将不会出现。
答案 2 :(得分:1)
感谢@redbirdo的最后一个答案,我找到了一个解决方案而没有弄乱控制器。 我只在模板中更改了几行。
<强> ControllerTest 强>
public function testUpdate()
{
$client = static::createClient();
$session = $client->getContainer()->get('session');
$session->set('testActionForm', 'abc');
$session->save(); // This line is important or you template won't see the variable
// ... tests
}
查看强>
{% if app.session.has('testActionForm') %}
{% set actionForm = path('parkingzone_update', { 'id': app.session.get('testActionForm') }) %}
{% else %}
{% set actionForm = path('parkingzone_update', { 'id': entity.id }) %}
{% endif %}
<form action="{{ actionForm }}" {{ form_enctype(form) }} method="POST" class="form-horizontal">
// ... rest of the form