Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Unit testing 黑盒还是白盒单元测试?_Unit Testing - Fatal编程技术网

Unit testing 黑盒还是白盒单元测试?

Unit testing 黑盒还是白盒单元测试?,unit-testing,Unit Testing,假设我有这样的代码: class SomeEntity { // ... some properties and methods here public function saveAndChangeState() { $result = $this->save(); // method for saving object somehow $this->changeState(); // changes state of ob

假设我有这样的代码:

class SomeEntity
{
    // ... some properties and methods here

    public function saveAndChangeState()
    {
        $result = $this->save(); // method for saving object somehow

        $this->changeState(); // changes state of object - e.g., sets some properties e.t.c.

        return $result;
    }

    public function save() { /* ... */ }

    public function changeState() { /* ... */ }
}
我可以为这个方法编写两种单元测试

白盒:

class SomeEntityTest extends TestCase 
{
    public function testSaveAndChangeState()
    {
        $expected = true;

        $SomeEntity = $this->getMock('SomeEntity', [
            // replace only these methods
            'save', 
            'changeState',
        ]);
        $SomeEntity->expects($this->once()) // should be called once
            ->method('save')
            ->willReturn($expected); // stub implementation will return $expected
        $SomeEntity->expects($this->once())
            ->method('changeState');

        $actual = $SomeEntity->saveAndChangeState();    

        $this->assertEquals($expected, $actual);
    }
}
和黑盒:

class SomeEntityTest extends TestCase 
{
    public function testSaveAndChangeState()
    {
        $SomeEntity = new SomeEntity();

        $result = $SomeEntity->saveAndChangeState();    

        // here come assertions about state - that I can see a persisted object, 
        // some properties of $SomeEntity have changed e.t.c.
    }
}
如果我选择whitebox:

  • testSaveAndChangeState()
    将更短
  • testSaveAndChangeState()
    如果我不适当地更改
    changeState()
    的实现,则不会失败-因此我的单元测试不会提醒我
    saveAndChangeState()
    工作不正确
如果我选择黑盒:

class SomeEntityTest extends TestCase 
{
    public function testSaveAndChangeState()
    {
        $SomeEntity = new SomeEntity();

        $result = $SomeEntity->saveAndChangeState();    

        // here come assertions about state - that I can see a persisted object, 
        // some properties of $SomeEntity have changed e.t.c.
    }
}
  • testSaveAndChangeState()
    将更加困难,因为我需要检查应用程序中被
    save()
    changeState()触及的每个部分
  • testSaveAndChangeState()
    如果我不适当地更改
    changeState()
    的实现,将提醒我有关
    saveAndChangeState()的问题
  • 我将有大量的代码重复-因为在
    testSaveAndChangeState()
    中,我将主要重复
    save()
    changeState()测试中的断言

我的问题是-我应该选择什么?

您应该使用whitebox,并为save()和changeState()添加测试。
我过去认为blackbox是一种可行的方法,但现在我使用whitebox,因为当我更改代码而测试失败时,测试向我展示了使用的方法是如何工作的,并帮助我记住所有需要考虑的情况。

最佳实践是分离业务关注点并测试对象之间的交互

将域对象(实体)与域交互者(实体服务)分离,并将域交互者与外部关注点(如数据持久性(数据库))分离

然后可以针对模拟对象进行黑盒测试,并确保EntityService正确调用数据持久层

如果您保持代码高度耦合,并将业务逻辑与检索/持久性/验证/其他关注点相结合,那么测试您的系统非常困难,很难发现bug,也很难更改

样本单元测试伪码

[TestMethod]
public void MyEntityService_SaveEntity_DataAccessSaveIsCalled()
{
    var inMemoryDatabase = new FakeDatabase(); 
    var service = new MyEntityService(inMemoryDatabase);
    var sampleEntity = new MyEntity { Name = "sampleObject" };

    service.Add(sampleEntity);

    Assert.IsTrue(inMemoryDatabase.LastSavedEntity == sampleEntity); 
}