ludofleury
4/3/2013 - 8:28 PM

atoum mock example

atoum mock example

<?php

namespace MyLittle\Bundle\BoxBundle\Tests\Units\Validator\Constraints;

use atoum\AtoumBundle\Test\Units;
use MyLittle\Bundle\BoxBundle\Validator\Constraints;
use Mock;

class StockValidator extends Units\Test
{
    protected $context;
    protected $validator;

    public function beforeTestMethod($method)
    {
        $this->context = $this->mockExecutionContext();
        $registry = $this->mockManagerRegistry();

        $this->validator = new Constraints\StockValidator($registry);
        $this->validator->initialize($this->context);
    }

    public function testNullIsInvalid()
    {
        $validator = $this->validator;
        $this
            ->exception(
                function () use ($validator) {
                    $validator->validate(null, new Constraints\Stock());
                }
            )
            ->isInstanceOf('\InvalidArgumentException')
            ->hasMessage('The data is not an object')
        ;
    }

    public function testObjectIsInvalid()
    {
        $validator = $this->validator;
        $this
            ->exception(
                function () use ($validator) {
                    $validator->validate(new \stdClass, new Constraints\Stock());
                }
            )
            ->isInstanceOf('\DomainException')
            ->hasMessage('The class "stdClass" must implement ProductInterface')
        ;
    }

    public function testNonUniqueSkuIsInvalid()
    {
        $registry = $this->mockManagerRegistry();
        $registry->getMockController()->getRepository = function ($className) {
            $repository = new Mock\Doctrine\Common\Persistence\ObjectRepository();
            $repository->getMockController()->findBy = [new Mock\MyLittle\Bundle\BoxBundle\Model\ProductInterface()];

            return $repository;
        };

        $this->validator = new Constraints\StockValidator($registry);
        $this->validator->initialize($this->context);

        $product = new Mock\MyLittle\Bundle\BoxBundle\Model\ProductInterface;

        $validator = $this->validator;
        $this->validator->validate($product, new Constraints\Stock());
        $this
            ->mock($this->context)
                ->call('addViolationAt')
                    ->withArguments('sku', 'The reference is already used.')
                    ->once()
        ;
    }

    /**
     * If the repository return an empty array, it means the current checked sku is new & unique
     */
    public function testNewUniqueSkuIsValid()
    {
        $product = new Mock\MyLittle\Bundle\BoxBundle\Model\ProductInterface;

        $validator = $this->validator;
        $this->validator->validate($product, new Constraints\Stock());
        $this
            ->mock($this->context)
                ->call('addViolationAt')
                    ->never()
        ;
    }

    /**
     * If the repository return an array with only 1 result, and the result is the same
     * object than the currently checked, the sku still unique.
     */
    public function testUniqueSkuIsValid()
    {
        $product = new Mock\MyLittle\Bundle\BoxBundle\Model\ProductInterface;

        $registry = $this->mockManagerRegistry();
        $registry->getMockController()->getRepository = function ($className) use ($product) {
            $repository = new Mock\Doctrine\Common\Persistence\ObjectRepository();
            $repository->getMockController()->findBy = [$product];

            return $repository;
        };

        $this->validator = new Constraints\StockValidator($registry);
        $this->validator->initialize($this->context);


        $validator = $this->validator;
        $this->validator->validate($product, new Constraints\Stock());
        $this
            ->mock($this->context)
                ->call('addViolationAt')
                    ->never()
        ;
    }

    /**
     * Mock a Symfony validation execution context
     *
     * @return Mock\Symfony\Component\Validator\ExecutionContext
     */
    private function mockExecutionContext()
    {
        $globalContext = new Mock\Symfony\Component\Validator\GlobalExecutionContextInterface();
        $globalContext->getMockController()->getViolations = new Mock\Symfony\Component\Validator\ConstraintViolationList();

        $translator = new Mock\Symfony\Component\Translation\TranslatorInterface();

        return new Mock\Symfony\Component\Validator\ExecutionContext($globalContext, $translator);
    }

    /**
     * Mock a Doctrine manager registry context
     *
     * @return Mock\Doctrine\Common\Persistence\ObjectRepository
     */
    private function mockManagerRegistry()
    {
        $registry = new Mock\Doctrine\Common\Persistence\ManagerRegistry();
        $registry->getMockController()->getRepository = function ($className) {
            $repository = new Mock\Doctrine\Common\Persistence\ObjectRepository();
            $repository->getMockController()->findBy = [];

            return $repository;
        };

        return $registry;
    }
}
<?php

namespace MyLittle\Bundle\BoxBundle\Validator\Constraints;

use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
use Doctrine\Common\Persistence\ManagerRegistry;
use MyLittle\Bundle\BoxBundle\Model\ProductInterface;
use DomainException;
use InvalidArgumentException;

/**
 * Ensure the SKU uniqueness for a product
 */
class StockValidator extends ConstraintValidator
{
    /**
     * @var ManagerRegistry
     */
    private $registry;

    /**
     * @param ManagerRegistry $registry
     */
    public function __construct(ManagerRegistry $registry)
    {
        $this->registry = $registry;
    }

    /**
     * {@inheritDoc}
     */
    public function validate($product, Constraint $constraint)
    {
        if (!is_object($product)) {
            throw new InvalidArgumentException(sprintf('The data is not an object'));
        }

        if (!$product instanceof ProductInterface) {
            throw new DomainException(sprintf('The class "%s" must implement ProductInterface', get_class($product)));
        }

        $className = $this->context->getClassName();
        $repository = $this->registry->getRepository($className);
        $result = $repository->findBy(['sku' => $product->getSku()]);

        if (1 < count($result) ||
            (1 === count($result) && $product !== ($result instanceof \Iterator ? $result->current() : current($result)))) {
            $this->context->addViolationAt('sku', 'The reference is already used.');
        }
    }
}