2009-01-15 11 views
3

Mon premier travail de programmation m'a présenté aux tests unitaires et au concept des objets simulés, mais quelque chose me semblait toujours mal.Comment écrire un objet Mock?

Disons que nous écrivions une application bancaire, et qu'il fallait se moquer d'un objet BankAccount:


    // boilerplate code 
    public interface IBankAccount { 
     void Deposit(int amount); 
     void Withdrawal(int amount); 
     int getBalance(); 
     int getAccountNumber(); 
    } 

    public interface IBankAccountFactory { 
     IBankAccount getAccount(int accountNumber); 
    } 

    public class ProductionBankAccountFactory implements IBankAccountFactory { 
     public IBankAccount getAccount(int accountNumber) { 
      return new RealBankAccount(accountNumber); 
     } 
    } 

    public class MockBankAccountFactory implements IBankAccountFactory { 
     public IBankAccount getAccount(int accountNumber) { 
      return new MockBankAccount(accountNumber); 
     } 
    } 

    public static class BankAccountFactory { 
     // ewww, singletons! 
     public static IBankAccountFactory Instance; 
    } 

    // finally, my actual business objects 
    public class MockBankAccount implements IBankAccount { 
     public MockBankAccount(int accountNumber) { ... } 
     // interface implementation 
    } 

    public class RealBankAccount implements IBankAccount { 
     public RealBankAccount(int accountNumber) { ... } 
     // interface implementation 
    } 

Chaque classe a un but:

  • Les interfaces d'usine et l'usine existent pour envelopper la constructeurs à nos objets simulacres et réels.
  • La classe BankAccountFactory statique nous permet d'affecter BankAccountFactory.Instance une instance de IRealBankAccountFactory ou MockBankAccountFactory au début de notre application de production ou des tests, respectivement.
  • Une fois que tout est correctement configuré, une classe peut saisir une instance de IBankAccount simplement en appelant:

    BankAccountFactory.Instance.getAccount(accountNum); 

Cela fonctionne, mais il en résulte beaucoup du code passe-partout. Je ne devrais pas avoir à écrire 5 nouvelles classes pour chaque classe que je veux me moquer. Je suis convaincu qu'il y a un moyen plus facile, donc je dois demander à la communauté SO:

Existe-t-il un moyen meilleur ou préféré d'écrire des objets fictifs?

[Modifier à ajouter:] J'apprécie les liens vers les moqueries et les cadres DI, mais en ce moment je travaille sur 500 applications KLOC, et au moins 60% du code est constitué de la maquette boilerplate cours dans le style ci-dessus. Je veux juste réduire la taille de la base de code sans réécrire de gros morceaux de code pour Yet-Another-Framework ™, donc cela m'aide plus à voir des classes fictives écrites à la main. :)

Répondre

0

Il existe des bibliothèques Mock qui simplifient le processus en vous permettant de spécifier l'objet et le comportement dans le code de tests unitaires.

Un bon exemple est la bibliothèque Moq (http://code.google.com/p/moq/)

1

Je suppose que ma première question est pourquoi vous devez utiliser un modèle d'usine pour envelopper la construction de vos objets; en particulier votre objet Mock. Puisque chaque test d'unité dans une suite devrait fonctionner complètement indépendamment de tous les autres tests unitaires, il semble que vous seriez capable d'instancier votre MockBankAccount directement dans la méthode setUp de votre classe de test unitaire, ou même dans le test lui-même. Si j'étais dans la situation ci-dessus, j'écrire quelque chose comme ceci:

public interface IBankAccount { 
    void Deposit(int amount); 
    void Withdrawal(int amount); 
    int getBalance(); 
    int getAccountNumber(); 
} 

public class MockBankAccountFactory implements IBankAccountFactory { 
    public IBankAccount getAccount(int accountNumber) { 
     return new MockBankAccount(accountNumber); 
    } 
} 

public class BankAccountUnitTest extends TestCase { 
    IBankAccount testBankAccount; 

    public void setUp() { 
     testBankAccount = new MockBankAccount(someAccountNumber); 
    } 

    // Unit tests here 
} 

Si vous utilisez l'usine pour test unitaire une autre classe que utilise IBankObject, alors vous devriez regarder dans dependency injection pour fournir un objet simulacre à cette classe, plutôt que d'avoir la classe à tester instancie un objet fantaisie.

Questions connexes