我正在努力寻找正确的方法来对我的 symfony 2 服务进行单元测试,这些服务使用原则或其他常见服务。
到目前为止我做了什么:
- 据我了解,控制器动作应该:
- 尽可能短
- 接受请求
- 从注入的服务执行所需的方法
- 以此为基础做出回应
- 本身就是一项服务
为了完成一个轻量级的操作,我尝试将逻辑封装到一个单独的服务中,该服务被注入到控制器中。
这很好地期望测试一切。
这是我当前的代码:
控制器
class SearchController
{
// search_helper, request and templating are controller-injected
protected $search_helper;
protected $request;
protected $templating;
// ...
public function searchAction()
{
$searchterm = strtolower($this->request->query->get('q'));
$result = $this->search_helper->findSamples($searchterm);
// Found a single result. Redirect to this page
if (is_string($result))
{
return new RedirectResponse($result, 301);
}
return new Response($this->templating->render('AlbiSampleBundle:Search:index.html.twig', array('results' => $result)));
}
}
搜索服务
class SearchHelper
{
// doctrine, session and min_query_len are controller-injected
protected $doctrine;
protected $session;
protected $min_query_len;
// ...
public function findSamples($searchterm)
{
if (strlen($searchterm) < $this->min_query_len)
{
$msg = 'Your search must contain at least 3 characters!';
$this->session->getFlashBag()->add('error', $msg);
return false;
}
$em = $this->doctrine->getManager();
$results = $em->getRepository('AlbiSampleBundle:Sample')->findPossibleSamples($searchterm);
// Execute a more advanced search, if std. search don't delivers a result
// ...
return $results;
}
}
如何正确测试此代码?
- 使用 phpunit_db 和 inmemory sqlite 数据库测试存储库 ✓</li>
- 可以通过简单的功能测试来测试该操作 ✓</li>
- 剩下的是搜索服务中的逻辑。例如 findSamples 方法
我的第一个想法是模拟依赖关系(实际上这是分离依赖关系的主要方面之一),但你不仅要模拟学说对象,还要模拟实体管理器和存储库。
$em = $this->doctrine->getManager();
$results = $em->getRepository('AlbiSampleBundle:Sample')->findPossibleSamples($searchterm);
我认为必须有更好的解决方案。这种嘲弄不仅需要很多 LOC,而且感觉也不对。测试将不必要地与 SUT 紧密耦合。
编辑
这是我想出的示例测试。使用模拟对象。测试不行。我意识到这需要更多的模拟对象,我觉得这不是正确的方法。
测试失败,因为SessionMock->getFlashbag
没有返回带有add
方法的 flashbag。
doctrine->getManager
返回没有EntityManager
。EntityManager
没有getRepository
办法。并且缺少存储库findPossibleSamples
。
class SearchHelperTest extends \PHPUnit_Framework_TestCase
{
private $router;
private $session;
private $doctrine;
public function setUp()
{
parent::setUp();
// ...
}
public function testSearchReturnValue()
{
$search_service = $this->createSearchHelper();
$this->assertFalse($search_service->findSamples('s'));
}
protected function createSearchHelper()
{
return new SearchHelper($this->doctrine, $this->router, $this->session, 3);
}
protected function getDoctrineMock()
{
return $this->getMock('Doctrine\Bundle\DoctrineBundle\Registry', array('getManager'), array(), '', false);
}
protected function getSessionMock()
{
return $this->getMock('Symfony\Component\HttpFoundation\Session\Session', array('getFlashBag'), array(), '', false);
}
protected function getRouterMock()
{
return $this->getMock('Symfony\Component\Routing\Router', array('generate'), array(), '', false);
}
}
希望社区可以帮助我,编写经过良好测试的代码:)
干杯