理解模拟测试的逻辑流程

时间:2014-12-17 15:01:48

标签: unit-testing symfony mocking phpunit

为了学习模拟测试的逻辑流程,我使用我的应用程序中的代码从Symfony article再现了测试失败。

背景:志愿者实体扩展了抽象类Person,它扩展了FOSUserBundle模型User。人员包括firstNamelastNamename的方法。名称返回lastName, firstName。下面显示的测试会返回:

--- Expected
+++ Actual
@@ @@
-'Borko, Benny'
+', ' 

如何修改此测试?更好的是,你怎么知道你的测试设计是什么时候而不是被测系统失败了?

编辑:请参阅下面提出的建议解决方案的结果

编辑#2:

不确定这是否相关:志愿者和其他两个实体通过继承映射映射到Person实体(请参阅PUGXMultiUserBundle)。

测试:

use Truckee\MatchingBundle\Entity\Volunteer;

class MockVolunteerTest extends \PHPUnit_Framework_TestCase
{
    public function testFullName()
    {
        // First, mock the object to be used in the test
        $volunteer = $this->getMock('\Truckee\MatchingBundle\Entity\Volunteer');
        $volunteer->expects($this->once())
                ->method('getFirstName')
                ->will($this->returnValue('Benny'));
        $volunteer->expects($this->once())
                ->method('getLastName')
                ->will($this->returnValue('Borko'));

        // Now, mock the repository so it returns the mock of the volunteer
        $volunteerRepository = $this->getMockBuilder('\Doctrine\ORM\EntityRepository')
                ->disableOriginalConstructor()
                ->getMock();
        $volunteerRepository->expects($this->once())
                ->method('find')
                ->will($this->returnValue($volunteer));

        // Last, mock the EntityManager to return the mock of the repository
        $em = $this->getMockBuilder('\Doctrine\Common\Persistence\ObjectManager')
                ->disableOriginalConstructor()
                ->getMock();
        $em->expects($this->once())
                ->method('getRepository')
                ->will($this->returnValue($volunteerRepository));

        $user = new Volunteer();
        $this->assertEquals('Borko, Benny', $user->getName());
    }
}

提议的解决方案:

class VolunteerTest extends \PHPUnit_Framework_TestCase
{
    /**
     * @var Volunteer
     */
    protected $object;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    protected function setUp()
    {
        $this->object = new Volunteer();
    }

    public function testGetterAndSetter() {
        $this->assertNull($this->object->setFirstName("Benny"));
        $this->assertEquals("Benny", $this->object->getFirstName());

        $this->assertNull($this->object->setLastName("Borko"));
        $this->assertEquals("Borko", $this->object->getLastName());

        $this->assertEquals('Borko, Benny', $this->object->getName());
    }    
}

测试结果:

  

无法断言Truckee \ MatchingBundle \ Entity \ Volunteer Object   & 0000000067c9c33f00000000680c6030(       ' ID' =>空值 ...       ' credentialsExpireAt' => null)为null。

2 个答案:

答案 0 :(得分:1)

模拟的主要目标是测试存储库或服务。有一种更简单的方法来测试您的实体:

class VolunteerTest extends \PHPUnit_Framework_TestCase {

    /**
     * @var Volunteer
     */
    protected $object;

    /**
     * Sets up the fixture, for example, opens a network connection.
     * This method is called before a test is executed.
     */
    protected function setUp()
    {
        $this->object = new Volunteer();
    }

    public function testGetterAndSetter() {
        $this->assertNull($this->object->setFirstName("Benny"));
        $this->assertEquals("Benny", $this->object->getFirstName());

        $this->assertNull($this->object->setLastName("Borko"));
        $this->assertEquals("Borko", $this->object->getLastName());
    }

}

答案 1 :(得分:0)

这里的答案是测试是不恰当的模拟测试。在阅读文章"An Introduction to Mock Object Testing"后,很明显该技术是模拟被测系统(对象)的依赖,而不是对象本身。在我尝试的测试中,志愿者实体是SUT所以它不应该被嘲笑。