我想爲我的應用程序做一些單元測試。這是我第一次使用PHPUnit進行管理(並且更通用一些單元測試),我希望得到一個建議。UnitTest and Database
首先,讓我們說,我有這個類
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方法,可以幫助我檢索一些實體並將它們放入會話中。
我用一些虛擬數據創建了一個測試數據庫,我會測試它們。
據我所知Doctrine的EntityManager有一個受保護的__construct()
方法。這意味着你不能使用「真正的」EntityManager,但你需要使用一個模擬的。 Repository等也可以做同樣的考慮。
所以我已經開發生產出的代碼是測試以下
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);
}
}
每個對象是一個嘲弄一個(除了住宿是一個「真正的」一節)。但對我來說,這個測試是無用的,因爲我無法從數據庫加載實體。
我完全知道這種測試是愚蠢的,但我很容易想象其他一些複雜的需要真實對象。
因此,詢問專家用戶,您對此有何看法?我如何着手進行更相關和適當的測試?
,而不是一個單元測試,在一個孤立的背景下工作,你應該做一個功能測試,通過固定裝置加載的數據,但是你必須自己建立這個賽程,所以是的,在特定情況下,您應該對存儲庫方法(或您的服務)進行功能測試。我的兩美分 – Matteo 2015-02-10 16:23:17
@Matteo:謝謝你的回答。我一定會做功能測試,但據我所知,如果你想要100%(或至少如果你嘗試)覆蓋的情況下,你也應該進行單元測試。我是我錯了?此外,對於你來說,可能是一個很好的情況,可能直接測試存儲庫方法,而對經理使用「虛擬」方法?在這種情況下,我可以爲這種方法覆蓋100%的情況。 – DonCallisto 2015-02-10 16:26:26
有時與夾具一起工作是一件頭痛的事情:您必須維護它們,並且您必須建立關係等等。通常,當我有複雜的業務邏輯時,我會進行單元測試,我使用控制器進行了一組功能測試(僅測試響應代碼,而不是基於DOM頁面元素),當我對自定義回購沒有真正的信心時方法我也做了功能測試。這只是我的看法,我是一個非常喜歡的TDD,但是......等待一位非常專業的人的回答!對不起,我很長的評論, – Matteo 2015-02-10 16:32:46