Как создать unit test создание экземпляра?
У меня есть класс Carpenter
, который работает с использованием объектов Lathe
и Wood
.
class Carpenter
{
function Work()
{
$tool = new Lathe();
$material = new Wood();
$tool->Apply($material);
}
}
Lathe
зависит от интерфейса с именем Material
, поэтому я могу легко unit test Lathe
дать ему подделку Material
в моем unit test. Wood
не зависит от чего-либо, поэтому его также можно легко протестировать.
interface Material {
// Various methods...
}
interface Tool {
function Apply(Material $m);
}
class Wood implements Material {
// Implementations of Material methods
}
class Lathe {
function Apply(Material $m) {
// Do processing
}
}
Однако Carpenter
зависит от конкретных классов Lathe
и Wood
, потому что он должен создавать экземпляры из них. Это означает, что, поскольку он в настоящее время стоит, я не могу unit test метод Work()
без непреднамеренного тестирования Lathe
и Wood
.
Как мне изменить свой дизайн на unit test Carpenter
?
Ответы
Ответ 1
Здесь есть несколько разных направлений:
- Используйте Инъекции конструктора и просто вставляйте инструмент и экземпляры материалов в плотника.
- Если инъекции экземпляров не работают по какой-либо причине (возможно, потому, что вам нужно создавать новые экземпляры для каждого вызова метода Work), вы можете добавить Абстрактные фабрики.
- Вы также можете использовать метод Factory Метод, описанный ctford, но для этого требуется, чтобы вы также создавали переопределения для тестирования, чтобы иметь возможность unit test, и хотя это полностью действительная вещь сделать это, это просто больше работы, и во многих случаях другие альтернативы лучше и гибче.
Ответ 2
Ключ состоит в том, чтобы отделить создание объекта от использования объекта в Carpenter
.
class Carpenter
{
function getTool() {
return new Lathe();
}
function getMaterial() {
return new Wood();
}
function Work()
{
$tool = getTool();
$material = getMaterial();
$tool->Apply($material);
}
}
Таким образом, вы можете переопределить методы getTool()
и getMaterial()
в классе TestCarpenter
и ввести свои подделки Material
и Tool
.
Методы getTool()
и getMaterial()
также могут быть протестированы отдельно.
Michael Feathers будет называть методы getTool()
и getMaterial()
"швами", потому что они являются точками, где подделки можно вставлять без изменение окружающего кода.