Was ist der beste Weg, eine Factory für Unit-Testobjekte zu erstellen?

Ich versuche TDD zu lernen und kämpfe mit der Erstellung von Fabriken für benutzerdefinierte Objekte. Wenn beispielsweise ein benutzerdefinierter Benutzertyp vorhanden ist und alle Benutzer dieses Typs über eine bestimmte function verfügen müssen, ist es mühsam, die WP_UnitTest-Factory zum Erstellen eines Benutzers zu verwenden und die functionalität anschließend in jedem Test manuell hinzuzufügen, bevor das Objekt verwendet wird. Da ich diese Objekte in einer Vielzahl von Testdateien verwenden muss, wäre es überflüssig, eine Factory-function in jeder Testdatei / -klasse zu haben, und es ist ein Problem, alle vier Varianten der Factory-Methoden manuell zu implementieren (create, create_and_get, create_many) und create_and_get_many).

Was ist der beste Weg, um eine Fabrik für solche Testobjekte zu erstellen?

Solutions Collecting From Web of "Was ist der beste Weg, eine Factory für Unit-Testobjekte zu erstellen?"

Ich habe eine Anleitung zum Erstellen eigener PHPUnit-Fabriken geschrieben . In diesem Fall müssen Sie jedoch nur die vorhandene Benutzerfactory WP_UnitTest_Factory_For_User . Wenn Sie sich die Quelle dieser class ansehen, werden Sie sehen, dass Sie nicht mehrere verschiedene Methoden implementieren müssen, nur eine: create_object() . Das wird von den anderen Methoden verwendet werden, die Sie erwähnen.

So sieht die Methode in der Benutzerfactory aus:

 function create_object( $args ) { return wp_insert_user( $args ); } 

Ziemlich einfach, nicht wahr?

Alles, was Sie tun müssen, ist, es zu ändern, um eine Kindklasse dieser Fabrik zu erstellen, etwa so:

 class WP_UnitTest_Factory_For_User_With_Cap extends WP_UnitTest_Factory_For_User { function create_object( $args ) { $user_id = parent::create_object( $args ); if ( $user_id ) { $user = new WP_User( $user_id ); $user->add_cap( 'my_custom_cap' ); } return $user_id; } } 

Dann können Sie in Ihrer setUp() Methode so etwas machen:

 $this->factory->user_with_cap = new WP_UnitTest_Factory_For_User_With_Cap( $this->factory ); 

Jetzt können Sie in Ihren Tests $this->factory->user durch $this->factory->user_with_cap an jeder Stelle $this->factory->user_with_cap , an der Sie einen Benutzer mit dieser zu erstellenden $this->factory->user_with_cap benötigen.


Ein alternativer Ansatz wäre es, eine eigene benutzerdefinierte abstrakte Testfallklasse zu erstellen, die ein Kind von WP_UnitTestCase und alle Ihre Testfälle daraus erweitert. Dann könnten Sie eine Factory-Methode für diese class erstellen. Dies funktioniert jedoch nur, wenn alle Ihre Testfälle von einem einzelnen Elternteil erweitert werden können, was beispielsweise bei einigen Ajax-Tests nicht der Fall ist.

Wenn ich richtig und richtig finde, ist das, was Sie suchen, eine gute Bibliothek zum Erstellen von Stubs und Mocks .

Wenn Sie PHPUnit verwenden, verfügt es über functionen. Siehe https://phpunit.de/manual/current/en/test-doubles.html#test-doubles

Angenommen, Sie haben eine class wie diese:

 namespace MyApp; class MyCustomUser { public function __construct(\WP_User $user) { $this->user = $user; } public function hasCapability($capability) { return $this->user->can($capability); } } 

Sie könnten ein Merkmal erstellen, das eine Benutzerfactory enthält und die Spottfunktion von PHPUnit nutzt:

 namespace MyApp\Tests; trait CreateUserTrait { protected function createUser(array $capabilitites) { $stub = $this->createMock(MyCustomUser::class); $has_capability = function($capability) use ($capabilitites) { return in_array($capability, $capabilitites, true); }; $stub->method('hasCapability')->will($this->returnCallback($has_capability)); } } 

An dieser Stelle in Ihren Testklassen können Sie dieses Merkmal verwenden und die Fabrik nutzen:

 namespace MyApp\Tests; use PHPUnit\Framework\TestCase; class UserMockTest extends TestCase { use CreateUserTrait; public function testUserFactoryWorks() { $userMock = $this->createUser(['create_post']); $this->assertTrue($userMock->hasCapability('create_post')); } } 

Natürlich sind Mocks und Stubs nützlich, wenn Sie andere Objekte testen müssen, die ein verspottetes Objekt verwenden. Du wirst den SUT nicht verspotten.

Ein schöner Nebeneffekt der Verwendung des Mocks ist, dass wir keine WordPress-function oder class im Test verwendet haben (selbst wenn das ursprüngliche Benutzerobjekt WordPress WP_User Objekt verwendet), sodass der Test ohne Laden von WordPress WP_User werden könnte Komponententest: Wenn Sie WordPress laden, wird es ein Integrationstest , kein Komponententest.

Viele Leute finden die spöttische Syntax von PHP etwas schwer zu verdauen . Wenn Sie einer von ihnen sind, sollten Sie einen Blick auf Mockery casting, die eine einfachere API hat.

Abhängig von Ihren Bedürfnissen könnte Faker auch eine große Hilfe sein.


Hinweis: Der obige Code erfordert PHP 5.5 und die angenommene PHPUnit-Version ist Version 5. *, die PHP 5.6+ erfordert