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:// | ||
| + | </ | ||
