2 回答
TA贡献1942条经验 获得超3个赞
创建工厂并 100% 测试该工厂。
据我了解,您的Crate班级既是实体又是工厂。Crate::getDetails您可以通过将此创建责任转移到工厂来进行重构。
这样,您就可以仅使用“Given, When, Then”结构对创建逻辑进行单元测试。查看这篇关于干净测试的帖子并导航到“测试应该简洁且有意义”。
拥有这种结构将帮助您分辨输入和输出是什么。例如:
CrateDetailsFactoryTest.php
class CrateDetailFactoryTest extends TestCase
{
public function testCreateCrateDetail(): void
{
// Given
$crate = $this->givenThereIsACrate();
$boxes = $this->givenThereAreTwoRedBoxes();
// When
$crateDetail = $this->crateDetailFactory->createCrateDetail(
$crate,
$boxes
);
// Then
// (Unnecessary instanceof, if you have strict return types)
self::assertInstanceOf(Detail::class, $crateDetail);
self::assertCount(2, $crateDetail->getBoxes());
self::assertEquals(
'red',
$crateDetail->getBoxes()->first()->getColor()
);
}
}
有了这个,你的创建逻辑就被覆盖了;从这里你可以简单地在你需要的地方注入你的工厂,并且在单元测试期间你只是模拟它:
板条箱服务.php
class CrateServiceTest extends TestCase
{
private $crateDetailFactory;
private $crateService;
public function setUp(): void
{
$this->crateDetailFactory = $this->prophesize(CrateDetailFactory::class);
$this->crateService = new CrateService(
$this->crateDetailFactory->reveal()
);
}
public function testAMethodThatNeedsCrateDetails(): void
{
// Given
$crate = $this->givenIHaveACrateWithTwoBoxesInIt();
$boxes = $crate->getBoxes();
// When
$result = $this->crateService->AMethodThatNeedsCrateDetails();
// Then
$this->crateDetailFactory->createCrateDetail($crate, $boxes)
->shouldBeCalledOnce();
}
}
我希望这很有用。干杯! :)
TA贡献2021条经验 获得超8个赞
使用上面的类,要正确地对其进行单元测试,您必须使用 DI 注入\Details::class其中一个getDetails()或 __constructor。然后为每个类的每个方法编写测试,模拟任何类依赖项/属性
class Create
{
public function getDetails(\Details $details)
}
//test.php
$mockDetails = $this->createMock(\Details::class)
->expects($this-once())
->method('item1')
->with('some_arg')
->willReturn('xyz')
$mockBox = $this-createMock(\Box::class)
......
$crate = new Create($boxMock);
$result = $crate->item1($mockDetails);
$this-assertSame('xyz', $result);
如果对一种方法感觉像您的嘲笑方式,那么您应该考虑重构以使代码更具可测试性。
至于多个项目的断言,在 PHPUnit 中,您可以使用 dataprovider 将一组值作为单独的测试传递给一个测试方法。 PHPUnit Docs - 数据提供者
您还可以为 \Details::class 编写单独的单元测试,断言传递给 \Details::setItem1($item) 的内容实际上是在 item1 属性上设置的。IE。
测试 \Details::class -
//test2
public function test() {
$details = new Details('some stuff');
$details->setItem1('expected');
self::assertSame('expected', $details->item1);
}
- 2 回答
- 0 关注
- 145 浏览
添加回答
举报
