pele_mele:stack_exchange:stack_overflow:27801219
Différences
Ci-dessous, les différences entre deux révisions de la page.
Les deux révisions précédentesRévision précédente | |||
pele_mele:stack_exchange:stack_overflow:27801219 [2024/11/23 03:57] – supprimée - modification externe (Date inconnue) 127.0.0.1 | pele_mele:stack_exchange:stack_overflow:27801219 [2024/11/23 03:57] (Version actuelle) – ↷ Page déplacée et renommée de pele_mele:stack_exchange:stackoverflow-27801219 à pele_mele:stack_exchange:stack_overflow:27801219 alexis | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
+ | ====== How to unit test a Symfony2 form when it uses a transformer linked to a database ====== | ||
+ | |||
+ | TLDR: I am new to unit tests and I have few questions: | ||
+ | |||
+ | - Are my transformer tests well written? | ||
+ | - Is there a way to decoupled my transformer tests from the database? | ||
+ | - How to test my form with the transformer using the database? | ||
+ | - Should I decouple my form from my transformer? | ||
+ | |||
+ | ------- | ||
+ | I don't know if my classes are too coupled, if my design is flawed or if my understanding of the unit tests is bad. | ||
+ | |||
+ | Here is some background. | ||
+ | I have a form object with different widgets. One of them is used within a model transformer. | ||
+ | This model transformer uses a connection to the database to retrieve the proper object. | ||
+ | |||
+ | Here is my code: | ||
+ | |||
+ | <code php> | ||
+ | class BookToStringTransformer implements DataTransformerInterface { | ||
+ | private $om; | ||
+ | |||
+ | public function __construct(ObjectManager $om) { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function transform($book) { | ||
+ | if (!$book instanceof Book) { | ||
+ | return ""; | ||
+ | } | ||
+ | |||
+ | return $book-> | ||
+ | } | ||
+ | |||
+ | public function reverseTransform($string) { | ||
+ | if (!is_string($string) || !$string) { | ||
+ | return null; | ||
+ | } | ||
+ | |||
+ | $book = $this-> | ||
+ | -> | ||
+ | -> | ||
+ | ; | ||
+ | |||
+ | if (null === $book) { | ||
+ | throw new TransformationFailedException(sprintf( | ||
+ | 'The book " | ||
+ | )); | ||
+ | } | ||
+ | |||
+ | return $book; | ||
+ | } | ||
+ | } | ||
+ | |||
+ | class ItemType extends AbstractType { | ||
+ | private $om; | ||
+ | |||
+ | public function __construct(ObjectManager $om) { | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function buildForm(FormBuilderInterface $builder, array $options) { | ||
+ | $bookTransformer = new BookToStringTransformer($this-> | ||
+ | $builder-> | ||
+ | ' | ||
+ | ))-> | ||
+ | } | ||
+ | |||
+ | public function setDefaultOptions(OptionsResolverInterface $resolver) { | ||
+ | $resolver-> | ||
+ | ' | ||
+ | )); | ||
+ | } | ||
+ | |||
+ | public function getName() { | ||
+ | return ' | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | I wrote unit tests for the transformer using the KernelTestCase | ||
+ | |||
+ | <code php> | ||
+ | class BookToStringTransformerTest extends KernelTestCase { | ||
+ | private $name = ' | ||
+ | private $em; | ||
+ | |||
+ | public function setUp() { | ||
+ | static:: | ||
+ | static:: | ||
+ | $this-> | ||
+ | -> | ||
+ | -> | ||
+ | } | ||
+ | |||
+ | public function testReverseTransform_whenNameExists_returnsBookObject() { | ||
+ | $transformer = new BookToStringTransformer($this-> | ||
+ | $book = $transformer-> | ||
+ | $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @expectedException Symfony\Component\Form\Exception\TransformationFailedException | ||
+ | */ | ||
+ | public function testReverseTransform_whenNameDoesNotExist_throwsException() { | ||
+ | $transformer = new BookToStringTransformer($this-> | ||
+ | $transformer-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @param mixed $invalid_parameter | ||
+ | * @dataProvider provideInvalidParameter | ||
+ | */ | ||
+ | public function testReverseTransform_whenParameterIsInvalid_returnsNull($invalid_parameter) { | ||
+ | $om = $this-> | ||
+ | $transformer = new BookToStringTransformer($om); | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @return array | ||
+ | */ | ||
+ | public function provideInvalidParameter() { | ||
+ | return [ | ||
+ | [null], | ||
+ | [false], | ||
+ | [true], | ||
+ | ['' | ||
+ | [[]], | ||
+ | [new \stdClass()], | ||
+ | ]; | ||
+ | } | ||
+ | |||
+ | public function testTransform_whenParameterIsBookObject_returnsName() { | ||
+ | $book = $this-> | ||
+ | -> | ||
+ | $om = $this-> | ||
+ | $transformer = new BookToStringTransformer($om); | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @param mixed $not_book | ||
+ | * @dataProvider provideInvalidBookObject | ||
+ | */ | ||
+ | public function testTransform_whenParameterIsNotBookObject_returnsEmptyString($not_book) { | ||
+ | $om = $this-> | ||
+ | $transformer = new BookToStringTransformer($om); | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @return array | ||
+ | */ | ||
+ | public function provideInvalidBookObject() { | ||
+ | return [ | ||
+ | [null], | ||
+ | [123], | ||
+ | [' | ||
+ | [[]], | ||
+ | [true], | ||
+ | [new \stdClass()], | ||
+ | ]; | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | As I am new to unit tests, I don't even know if it is the proper way to test that transformer. | ||
+ | I start writing tests for the form object. I am using the TypeTestCase but there is no simple way to get the connection to the database and I can't use the KernelTestCase. | ||
+ | |||
+ | <code php> | ||
+ | class ItemTypeTest extends TypeTestCase { | ||
+ | /** | ||
+ | * @expectedException \PHPUnit_Framework_Error | ||
+ | */ | ||
+ | public function test_whenCreatedWithNoParameters_raiseException() { | ||
+ | new ItemType(); | ||
+ | } | ||
+ | |||
+ | /** | ||
+ | * @expectedException \PHPUnit_Framework_Error | ||
+ | */ | ||
+ | public function test_whenCreatedWithBadParameters_raiseException() { | ||
+ | new ItemType(123); | ||
+ | } | ||
+ | |||
+ | public function test_whenCreatedWithGoodParameters_createsFormObject() { | ||
+ | $om = $this-> | ||
+ | $type = new ItemType($om); | ||
+ | $form = $this-> | ||
+ | $this-> | ||
+ | } | ||
+ | |||
+ | public function test_whenSubmittedWithGoodData() { | ||
+ | $formData = array( | ||
+ | ' | ||
+ | ); | ||
+ | |||
+ | $om = $this-> | ||
+ | $type = new ItemType($om); | ||
+ | $form = $this-> | ||
+ | |||
+ | $form-> | ||
+ | } | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | The last test fails because the transformer does get access to the database since I am passing a mock to the form. So should I get a real object (meaning classes are too coupled) or should I find an other way. | ||
+ | |||
+ | Thank you | ||
+ | <WRAP help> | ||
+ | The approach is good, in the last method you must mock the repo object and the repo response. In example try this code: | ||
+ | <code php> | ||
+ | public function test_whenSubmittedWithGoodData() { | ||
+ | $formData = array( | ||
+ | ' | ||
+ | ); | ||
+ | |||
+ | $om = $this-> | ||
+ | |||
+ | $repoMock= $this-> | ||
+ | |||
+ | $om | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | |||
+ | |||
+ | $repoMock | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | -> | ||
+ | |||
+ | $type = new ItemType($om); | ||
+ | $form = $this-> | ||
+ | |||
+ | $form-> | ||
+ | } | ||
+ | </ | ||
+ | </ | ||
+ | <WRAP info> | ||
+ | [[https:// | ||
+ | </ | ||