我想为我的应用程序进行一些单元测试。由于这是我第一次使用 PHPUnit(以及一般意义上的单元测试)进行管理,我想得到建议。
首先,假设我有这个类(class)
class LodgingManager
{
private $session;
private $entity_manager;
public function __construct(Session $session, EntityManager $em)
{
$this->session = $session;
$this->entity_manager = $em;
}
public function loadLodgingList()
{
//If I've already fetched lodgings from db, use the session one.
//Everytime a lodging is added, session is refreshed
$lodging_list = $this->session->get('lodging_list');
if (!$lodging_list) {
$lodging_repo = $this->entity_manager->getRepository('KoobiBookingEngineBundle:Lodging');
$lodging_list = $lodging_repo->getAllForList();
$this->session->set('lodging_list', $lodging_list);
}
return $lodging_list;
}
[...]
}
这是一个简单而愚蠢的方法,但是,从这里开始对我来说似乎非常有用,因为代码并不复杂。正如每个人都可以看到的,我使用自定义 DQL 方法来帮助我检索一些实体并将它们放入 session 中。
我创建了一个包含一些虚拟数据的测试数据库,我想测试它们。
据我所知,Doctrine 的 EntityManager 有一个 protected __construct()
方法。这意味着您不能使用“真正的”EntityManager,但需要使用模拟的。对于存储库等也可以进行同样的考虑。
所以我生成的代码如下
class LodgingManagerTest extends \PHPUnit_Framework_TestCase
{
const LODGING_CLASS = 'KoobiBookingEngineBundle:Lodging';
/** @var LodgingManager */
protected $lodging_manager;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $em;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $repository;
/** @var \PHPUnit_Framework_MockObject_MockObject */
protected $session;
public function setUp()
{
$lodging_array_collection = new ArrayCollection();
$lodging = $this->getMock('Koobi\BookingEngineBundle\Entity\Lodging');
$lodging_array_collection->add($lodging);
$repository = $this->getMockBuilder('Koobi\BookingEngineBundle\Repository\LodgingRepository')
->disableOriginalconstructor()
->getMock();
$repository->expects($this->once())
->method('getAllForList')
->will($this->returnValue($lodging_array_collection));
$this->repository = $repository;
$em = $this->getMockBuilder('Doctrine\ORM\EntityManager')
->disableOriginalconstructor()
->getMock();
$em->expects($this->once())
->method('getRepository')
->with($this->equalTo(static::LODGING_CLASS))
->will($this->returnValue($repository));
$this->em = $em;
$this->session = new Session(new MockArraySessionStorage());
$this->lodging_manager = $this->createLodgingManager($this->session, $this->em);
}
public function testLoadLodgingList()
{
$lodging_list = $this->lodging_manager->loadLodgingList();
$this->assertCount(1, $lodging_list);
}
}
每个测试对象都是模拟对象(住宿除外,它是“真实”对象)。但对我来说这个测试毫无用处,因为我无法从数据库加载真实的实体。
我完全知道这种测试很愚蠢,但我可以轻松想象其他需要真实对象的复杂测试。
那么请问专家用户,您对此有何看法?我怎样才能继续进行更相关和更合适的测试?
最佳答案
您应该重构代码,将“简单、愚蠢”的 dao 与其他所有内容( session 管理和业务逻辑)分开。然后将您的测试分为 2 或 3 组。
单元测试:与环境(也与数据库)隔离的测试组件。在此测试中,您模拟您的数据库(entityManager、存储库,但在您的技术中称为它),并检查这些模拟是否按预期调用
数据库测试:您使用您的真实实体管理器、存储库和 mysql/oracle/whatever 来测试您的 sql/orm 代码是否正常工作。您仅测试数据库代码,没有任何业务逻辑或 session 管理
端到端测试。您启动整个应用程序并模拟用户单击 Web 界面
关于unit-testing - 单元测试和数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28436438/