控制器单元测试 (Symfony)
Unit Tests for Controller (Symfony)
如何为这个控制器创建单元测试?我知道如何实现功能,但对单元测试一无所知...
class CatalogController extends Controller
{
/**
* @param Request $request
* @return View
*/
public function getAllAction(Request $request)
{
$name = $request->query->get('name');
$result = $this->getDoctrine()->getRepository('AppBundle:Category')->findBy(array('name' => $name));
if ($result === NULL) {
return new View("Catalog not found", Response::HTTP_NOT_FOUND);
}
return new View($result,Response::HTTP_OK);
}
/**
* @param $id
* @return View|object
*/
public function getAction($id)
{
$result = $this->getDoctrine()->getRepository('AppBundle:Category')->find($id);
if (!$result instanceof Category) {
return new View("ID: " . $id . " not found", Response::HTTP_NOT_FOUND);
}
return new View($result, Response::HTTP_OK);
}
/**
* @param Request $request
* @return View|Response
*/
public function postAction(Request $request)
{
$serializer = $this->get('jms_serializer');
$content = $request->getContent();
$category = $serializer->deserialize($content,'AppBundle\Entity\Category','json');
$errors = $this->get('validator')->validate($category);
if (count($errors) > 0) {
return new View("NAME LENGTH MUST BE >4",Response::HTTP_BAD_REQUEST);
} else {
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
return new View($category, Response::HTTP_OK);
}}}
................................................ ..................................................... ..................................................... .....................
如果您想单独测试 PHP Class 与单元测试,您应该注入您在 class.
中使用的所有服务
作为起点:
/** @test */
public function it_should_return_a_view(){
$controller = new CatalogController();
$result = $controller->getAllAction($mockedRequest, $mockedRepository);
$this->assertInstanceOf(View::class, $result);
}
您需要模拟请求和存储库,这只有在将其注入方法或通过 class.
的构造函数注入时才有可能
希望对您的单元测试有所帮助。
有一个老笑话,以"How do you get down off an elephant?"开头,以"You don't, you get down off a duck"结尾。仍然让我崩溃。
重点是,如果您让控制器操作保持苗条,那么您可能根本不需要对它们进行单元测试。当然,100% 代码覆盖率执行者会不同意这一点。
但是,如果您决心测试它们,那么您将需要进行一些认真的重构以保持您自己的理智。让我们看看您的 getAllAction:
public function getAllAction(Request $request)
{
$name = $request->query->get('name');
因此您需要模拟一个请求对象,然后模拟一个包对象,然后添加一个测试以查看是否使用名称参数调用了 get。充其量是痛苦的。然而,Symfony 实际上可以自动注入请求参数:
public function getAllAction(string $name)
{
就是你所需要的。更少的代码。易于测试。有什么不喜欢的?
$result = $this->getDoctrine()->getRepository('AppBundle:Category')->findBy(array('name' => $name));
现在这可能是一个真正的问题。如果您查看 getDoctrine 代码,您会发现它需要一个容器,该容器包含一个学说实体管理器注册表 class,该注册表又包含一个实体管理器,该实体管理器随后包含存储库。你真的想模拟所有这些对象并将它们串在一起吗?与调试实际代码相比,您将花费更多的时间调试测试。作为奖励,您的代码实际上不再适用于已经脱离服务定位器模式的 SF4。
幸运的是,使用动作注入很容易修复:
public function getAllAction(string $name, CategoryRepository $categoryRepository)
您将需要做一些研究来了解如何将您的存储库定义为服务,但它并不难测试,而且相当容易测试。我们又一次摆脱了相当讨厌的代码行。
现在这有点有趣:
return new View("Catalog not found", Response::HTTP_NOT_FOUND);
对于单元测试,我们当然没有兴趣测试视图 class 本身。相反,我们只想知道视图是否是使用正确的参数构造的。没有简单的方法来拦截新操作。
相反,我们可以定义并注入一个 ViewFactory
class ViewFactory
public create($data,$status)
return new View($data,$status)
所以现在模拟视图工厂和测试创建方法已经很容易了。作为奖励,控制器代码与视图的联系并不那么紧密class。
因此,如果您真的觉得有必要对这些类型的操作进行单元测试,那么就卷起袖子开始重构吧。我可能会补充说,在 Symfony 中查看新的自动装配功能也是一个好主意。
如何为这个控制器创建单元测试?我知道如何实现功能,但对单元测试一无所知...
class CatalogController extends Controller
{
/**
* @param Request $request
* @return View
*/
public function getAllAction(Request $request)
{
$name = $request->query->get('name');
$result = $this->getDoctrine()->getRepository('AppBundle:Category')->findBy(array('name' => $name));
if ($result === NULL) {
return new View("Catalog not found", Response::HTTP_NOT_FOUND);
}
return new View($result,Response::HTTP_OK);
}
/**
* @param $id
* @return View|object
*/
public function getAction($id)
{
$result = $this->getDoctrine()->getRepository('AppBundle:Category')->find($id);
if (!$result instanceof Category) {
return new View("ID: " . $id . " not found", Response::HTTP_NOT_FOUND);
}
return new View($result, Response::HTTP_OK);
}
/**
* @param Request $request
* @return View|Response
*/
public function postAction(Request $request)
{
$serializer = $this->get('jms_serializer');
$content = $request->getContent();
$category = $serializer->deserialize($content,'AppBundle\Entity\Category','json');
$errors = $this->get('validator')->validate($category);
if (count($errors) > 0) {
return new View("NAME LENGTH MUST BE >4",Response::HTTP_BAD_REQUEST);
} else {
$em = $this->getDoctrine()->getManager();
$em->persist($category);
$em->flush();
return new View($category, Response::HTTP_OK);
}}}
................................................ ..................................................... ..................................................... .....................
如果您想单独测试 PHP Class 与单元测试,您应该注入您在 class.
中使用的所有服务作为起点:
/** @test */
public function it_should_return_a_view(){
$controller = new CatalogController();
$result = $controller->getAllAction($mockedRequest, $mockedRepository);
$this->assertInstanceOf(View::class, $result);
}
您需要模拟请求和存储库,这只有在将其注入方法或通过 class.
的构造函数注入时才有可能希望对您的单元测试有所帮助。
有一个老笑话,以"How do you get down off an elephant?"开头,以"You don't, you get down off a duck"结尾。仍然让我崩溃。
重点是,如果您让控制器操作保持苗条,那么您可能根本不需要对它们进行单元测试。当然,100% 代码覆盖率执行者会不同意这一点。
但是,如果您决心测试它们,那么您将需要进行一些认真的重构以保持您自己的理智。让我们看看您的 getAllAction:
public function getAllAction(Request $request)
{
$name = $request->query->get('name');
因此您需要模拟一个请求对象,然后模拟一个包对象,然后添加一个测试以查看是否使用名称参数调用了 get。充其量是痛苦的。然而,Symfony 实际上可以自动注入请求参数:
public function getAllAction(string $name)
{
就是你所需要的。更少的代码。易于测试。有什么不喜欢的?
$result = $this->getDoctrine()->getRepository('AppBundle:Category')->findBy(array('name' => $name));
现在这可能是一个真正的问题。如果您查看 getDoctrine 代码,您会发现它需要一个容器,该容器包含一个学说实体管理器注册表 class,该注册表又包含一个实体管理器,该实体管理器随后包含存储库。你真的想模拟所有这些对象并将它们串在一起吗?与调试实际代码相比,您将花费更多的时间调试测试。作为奖励,您的代码实际上不再适用于已经脱离服务定位器模式的 SF4。
幸运的是,使用动作注入很容易修复:
public function getAllAction(string $name, CategoryRepository $categoryRepository)
您将需要做一些研究来了解如何将您的存储库定义为服务,但它并不难测试,而且相当容易测试。我们又一次摆脱了相当讨厌的代码行。
现在这有点有趣:
return new View("Catalog not found", Response::HTTP_NOT_FOUND);
对于单元测试,我们当然没有兴趣测试视图 class 本身。相反,我们只想知道视图是否是使用正确的参数构造的。没有简单的方法来拦截新操作。
相反,我们可以定义并注入一个 ViewFactory
class ViewFactory
public create($data,$status)
return new View($data,$status)
所以现在模拟视图工厂和测试创建方法已经很容易了。作为奖励,控制器代码与视图的联系并不那么紧密class。
因此,如果您真的觉得有必要对这些类型的操作进行单元测试,那么就卷起袖子开始重构吧。我可能会补充说,在 Symfony 中查看新的自动装配功能也是一个好主意。