Question

Je l'ai regardé à travers les différentes questions sur les tests unitaires mais ne peut pas trouver un qui répond spécifiquement à cette question.

J'ai plusieurs classes PHP qui contiennent des fonctions qui ressemblent à ceci:

    static function _setSuspended($Suspended, $UserID)
    {
        try {
            $con = Propel::getConnection();

            $c1 = new Criteria();
            $c1->add(DomainsPeer::USERID,$UserID);

            $update = new Criteria();
            $update->add(DomainsPeer::SUSPENDED,$Suspended);

            BasePeer::doUpdate($c1, $update, $con);

            return true;
        } catch(PropelException $e) {
            return $e->getMessage();
        }
    }

J'utilise Propel comme mon ORM. Je l'ai lu divers sujets de tests unitaires qui parlent de la création de « Mocks » et « Stubs » et ce pas, mais je ne l'ai pas été en mesure de trouver quelque chose qui vous indique précisément comment tester une fonction comme ci-dessus.

Ma pensée va quelque chose comme: je dois tester la fonction ci-dessus, donc je voudrais l'appeler. Mais si je l'appelle, il utilise Propel comme ORM et selon les principes de tests unitaires fallait isoler chaque fonction par lui-même.

Je ne vois pas une façon de le faire. Que suis-je manque ici?

Était-ce utile?

La solution

J'ai trouvé que se moquant de la ORM ne me donne pas confiance parce que la configuration ORM n'est testé. ORM ont aussi beaucoup d'action à un effet à distance qui peuvent donner fausse confiance avec les tests unitaires. Mocking le pilote de base de données ou de fournir une autre base de données en mémoire me donne confiance beaucoup plus mon code est correct et il est à peu près aussi difficile que se moquant de la ORM.

SQLite est une grande base de données en mémoire pour les tests unitaires. Il est sur la liste de base de données pris en charge PDO. (AOP est le pilote de base de données Propel 1.3.) Si vous ne souhaitez pas utiliser une base de données en mémoire, vous pourriez être en mesure de trouver une maquette PDO déjà écrit.

Autres conseils

Ceci est une réponse générique que je ne suis pas au courant du tout Propel et seulement un peu plus familier avec PHP. La réponse de base est que vous utilisez l'injection de dépendance. Au lieu de se référer directement à votre ORM, vous créez une enveloppe autour d'elle, puis injecter l'emballage dans votre classe / fonction à utiliser réellement. Pour faire des tests unitaires, vous créez une version fausse ou faux de l'emballage qui ne l'interface pas au ORM mais vous permet de configurer les réponses de l'emballage à vos invocations de méthode. Cela vous permet de factoriser l'ORM lorsque l'appareil à tester vos fonctions.

Je suis en train d'aborder le même problème tout en bâtissant un PHPUnit plugin pour le Symfony. J'ai fini par approcher de la même cadre test Django -. utiliser une base de données / connexion séparée, et de détruire et reconstruire avant chaque test

Je trouve que j'ai pu sortir avec la reconstruction que la base de données de test avant le premier test dans un essai (ou si un test indique explicitement à); avant que les autres tests, il supprime simplement toutes les données pour accélérer les choses un peu.

J'ai lu Misko blog de Hevery sur les tests beaucoup ces derniers temps. Il couvre cette situation; vous auriez besoin d'utiliser DI (injection de dépendance).

Je me bats avec ce un peu aussi, et je l'utilise aussi Propel.

Pour un, vous pouvez déplacer la méthode « suspendre » à la classe « objet » plutôt que le pair. Pour cette fonction particulière de toute façon, vous n'avez pas besoin d'utiliser les méthodes statiques pour y parvenir. Votre API pourrait ressembler à:

MyObjectPeer::retrieveByPK(1)->suspend();

Ce serait testable par des méthodes normales de tests unitaires.

Si c'est vraiment la base de données qui doit être testé, alors vous devez avoir AFAIK en fait la base de données impliqués dans le test. J'utilise ltree et PostGIS beaucoup dans mon projet en cours et je ne peux pas penser à une autre façon d'exécuter des tests unitaires pour la logique du modèle qui dépend de la DB autre que de l'inclure dans mes tests.

Ceci est un exemple d'une classe avec dépendance matérielle qui ne peut être testable.

Nous pourrions être en mesure de tester avec une connexion à une autre base de données mais, ce n'est pas un test de l'unité plus, mais un test d'intégration.

La meilleure alternative que je pense est d'avoir une classe QueryFactory qui envelopper toutes les différentes méthodes que vous avez besoin et, vous serez en mesure de se moquer de lui.

Tout d'abord dans le premier je crée une interface

interface iQueryFactory
{
    function firstFunction($argument);
    function secondFunction($argument, $argument2);
}

Le QueryFactory avec toute votre demande ORM nous avons besoin

class QueryFactory implements iQueryFactory
{
    function firstFunction($argument) 
    {
        // ORM thing
    }

    function secondFunction($argument, $argument2)
    {
        // ORM stuff
    }
}

Il est logique d'affaires avec l'injection de l'usine de requête

class BusinessLogic 
{
    protected $queryFactory;

    function __construct($queryFactoryInjection) 
    {
        $this->queryFactory= $queryFactoryInjection;
    }

    function yourFunctionInYourBusinessLogique($argument, $argument2) 
    {
        // business logique

        try {
            $this->queryFactory->secondFunction($argument, $argument2);
        } catch (\Exception $e) {
            // log
            // return thing
        }

        // return stuff
    }
}

La partie fausse, notez que je ne pas utiliser un cadre de simulation pour mon exemple (BTW vous pouvez créer un setter de réponse)

class QueryFactoryMock implements iQueryFactory
{
    function firstFunction($argument) 
    {
        if (is_null($argument)) 
        {
            throw new \Exception("");
        } 
        else 
        {
            return "succes";
        }
    }

    function firstFunction($argument, $argument2) 
    { 
        // sutff  
    }
}

Puis enfin les tests unitaires qui testent notre logique métier avec la mise en œuvre simulée

class BusinessLogicTest extends PHPUnit_Framework_TestCase 
{
    public function setUp() 
    {
        require_once "BusinessLogic.php";
    }

    public function testFirstFunction_WhenInsertGoodName() 
    {
        $queryMockup = new QueryFactoryMock();
        $businessLogicObject = new BusinessLogic($queryMockup);
        $response = $businessLogicObject ->firstFunction("fabien");

        $this->assertEquals($response, "succes");
    }

    public function testFirstFunction_WhenInsetNull() 
    {
        $queryMockup = new QueryFactoryMock();
        $businessLogicObject = new BusinessLogic($queryMockup);
        $response = $businessLogicObject->firstFunction(null);

        $this->assertEquals($response, "fail");
    }
}
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top