Разъяснения по объектам бога, типу теста, покрытию теста и как сделать класс модульно-тестируемым

В настоящее время я пытаюсь протестировать конструктор класса в модульном тесте.

Я не уверен, является ли экземпляр этого объекта «божественным объектом», я бы сказал, что это не так, поскольку он объединяет только несколько других компонентов.

В любом случае, я открыт для лучшего дизайна.

Таким образом, грубая диаграмма классов выглядит следующим образом

введите описание изображения здесь

World это подозреваемый класс бога. Его зависимости, ServiceProvider, CommandRegistry, EventHub а также Environment вводятся через его конструктор.

В своем конструкторе World делает следующие вещи:

  1. хранить его зависимости в приватных полях
  2. зарегистрировать крючок ($this, 'onCommandIssued') с eventHub таким образом world получает уведомления обо всех командах, выполняемых не через world сам экземпляр (world имея также метод executeCommand)
  3. рассказать окружающей среде принять мир: $this->environment->adoptWorld($this), Роль среды состоит в том, чтобы адаптировать мир к некоторым реалиям работающей среды, например, веб-среда имеет некоторые специфические сервисы, которые недоступны в среде консольного приложения (например, сервис «сеанс»)
  4. уведомить через центр событий, что строительство мира завершено: $this->eventHub->notify(new WorldConstructedEvent($this));

Может быть, это выглядит как тяжелый конструктор, но это просто то, что определяется как «конструирование мира».

World в основном шлюз для отправки команд (как объекты передачи данных, через World::executeCommand()) к которым разные сервисы могут регистрировать хуки.

Теперь к проблемам / вопросам:

  1. Я пытаюсь провести юнит-тестирование этого конструктора, но я должен добавить несколько @uses аннотации, что делает его похожим на что-либо еще, кроме модульного теста. Что это, функциональный тест? Unit-тестирование World Неловко, тестировать что-либо еще действительно тривиально, и я не вижу, чтобы эта проблема возникала ни в одном другом тесте, что заставляет меня задаться вопросом, почему это так и как улучшить дизайн.
  2. Является World объект бога? Все, что он делает, это объединяет другие компоненты и пересылает вызовы к ним.
  3. Как правильно юнит-тестировать методы World? Если я использую много заглушек и внедряю их в зависимости, это все-таки модульное тестирование?

Это для ориентированного на домен (сложного) приложения, и я открыт для предложений, которые могли бы сделать дизайн лучше (тестируемым и отделенным).

Пожалуйста, дайте мне знать в комментариях, если вам нужно больше деталей.

Поскольку я не знаю, к чему приведет эта дискуссия, я могу уточнить свои вопросы.

0

Решение

Наконец-то я приступил к модульному тестированию класса, установив правильные ожидания и смоделировав зависимости:

<?php

namespace Common\World;

use TestFramework\TestCase;

class WorldTest extends TestCase
{
/**
* @test
* @covers \Common\World\World::__construct
* @uses   \Common\World\World::setEventHub
* @uses   \Common\World\Event\Adopted
*/
public function construction()
{
/** @var \Common\World\Environment $environmentStub |\PHPUnit_Framework_MockObject_MockObject */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
/** @var \Common\World\EventHub|\PHPUnit_Framework_MockObject_MockObject $eventHubStub */
$eventHubStub = $this->getMock('Common\World\EventHub');

$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnCallback(function (World $world) use ($eventHubStub) {
$world->setEventHub($eventHubStub);
return true;
}));
$eventHubStub->expects($this->once())
->method('trigger')
->with($this->isInstanceOf('Common\World\Event\Adopted'));
$this->assertInstanceOf('Common\World\World', new World($environmentStub));
}

/**
* @test
* @covers \Common\World\World::__construct
* @expectedException \RuntimeException
* @expectedExceptionMessage the environment has rejected this world for incompatibility reasons
*/
public function construction_rejected()
{
/** @var \Common\World\Environment $environmentStub */
$environmentStub = $this->getMockBuilder('Common\World\Environment')->getMock();
$environmentStub->expects($this->once())
->method('adoptWorld')
->will($this->returnValue(false));

new World($environmentStub);
}}
0

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]