2016-10-07 1 views
0

[07/10/06 4:00 Exemple de code édité] J'essaie de tester du code (en utilisant JMockIt avec TestNG) sans toucher à la base de données, mais il semble qu'une méthode mockée est encore en fait appelé. Voici la configuration simplifiée:JMockIt Mocked Méthode non moqueuse

class DBRow { 
    public DBRow() { } 
    public DBRow(Object obj) { 
     initialize(obj); 
    } 
    public void insert() { 
     actuallyAddRowToDatabase(); 
    } 
} 

class MyObject extends DBRow { 
    MyObject(Object obj) { 
     super(obj); 
    } 
    public void insert(Object obj) { 
     doSomething(obj); 
     insert(); 
    } 
} 

class Factory { 
    static MyObject createObject(Object obj1, Object obj2) { 
     MyObject newObj = new MyObject(obj1); 
     newObj.insert(obj2); 
     return newObj; 
    } 
} 

Je voulais railler l'opération d'insertion pour empêcher une insertion dans la base de données réelle, alors j'ai essayé quelque chose comme ceci:

@Test 
public void testCreation() { 
    new Expectations(MyObject.class) { 
     MyObject mock = new MyObject(null) { 
      @Mock 
      public void insert(Object obj) { } 
     }; 
    { 
     new MyObject(anyString); result = mock; 
    }}; 

    MyObject test = Factory.createObject("something", "something else"); 
} 

Mais il semble que le vrai insert(Object) est toujours appelé. Je précise que la classe est ridiculisée, donc toutes les instances devraient être moquées, n'est-ce pas? Et je spécifie que la méthode d'insertion doit être raillée, alors pourquoi la méthode réelle serait appelée?

Il y a aussi un deuxième problème avec ce qui précède. Lorsque je définis la classe mock dans le bloc Expectations (comme ci-dessus), il semble que seul le constructeur Row() est appelé au lieu de Row(Object), et donc l'objet n'est pas correctement initialisé. J'ai corrigé ceci en le déplaçant dans une méthode @BeforeTest et en instanciant la classe là. Voilà ce qui ressemble à:

private MyObject mock; 

@BeforeTest 
public void beforeTest() { 
    new MockUp<MyObject>() { 
     @Mock 
     public void insert(Object obj) { } 
    }; 
    mock = new MyObject("something"); 
} 

@Test 
public void testCreation() { 
    new Expectations(MyObject.class) {{ 
     new MyObject(anyString); result = mock; 
    }}; 

    MyObject test = Factory.createObject("something", "something else"); 
} 

Donc cela semble obtenir le constructeur correct d'être appelé, mais il semble encore que insert() est appelé aussi bien. Des idées?

Répondre

0

J'ai finalement pu écrire mes tests de telle sorte que le bon constructeur a été appelé et qu'aucune opération de base de données n'a été effectuée. Je pense qu'une partie du problème était que l'une des méthodes dans le bloc Expectations obtenait un objet différent de ce à quoi je m'attendais pour un paramètre qui ne m'intéressait pas. Et je pense que l'autre partie de mon problème était de mélanger les rôles d'une classe MockUp et des enregistrements Expectations.

Le code testé n'a pas changé. Voici mon exemple simplifié à nouveau pour des raisons pratiques:

class DBRow { 
    public DBRow() { } 
    public DBRow(Object obj) { 
     initialize(obj); 
    } 
    public void insert() { 
     actuallyAddRowToDatabase(); 
    } 
} 

class MyObject extends DBRow { 
    MyObject(Object obj) { 
     super(obj); 
    } 
    public void insert(Object obj) { 
     doSomething(obj); 
     insert(); 
    } 
} 

class Factory { 
    static MyObject createObject(Object obj1, Object obj2) { 
     MyObject newObj = new MyObject(obj1); 
     newObj.insert(obj2); 
     return newObj; 
    } 
} 

est ici essentiellement ce que j'ai finalement fini avec pour le code de test:

Object something; 
Object somethingElse; 

@BeforeTest 
public void beforeTest() { 
    new MockUp<MyObject>() { 
     @Mock 
     public void insert() { } // override the "actual" DB insert 
    };       // of Row.insert() 
} 

@Test 
public void testCreation() { 
    MyObject mock = new MyObject(something); // object correctly init'd 
               // by Row.initialize(Object) 
    new Expectations(MyObject.class) {{ 
     new MyObject(something);  result = mock; 
     mock.insert(somethingElse); 
    }}; 

    MyObject test = Factory.createObject(something, somethingElse); 
} 

Les points clés sont que A) j'ai créé une classe Mockup pour remplacer le DB opérations, et B) créé une instance locale de cette instance partiellement simulée pour enregistrer mes attentes.

0

Vous n'utilisez pas l'objet moqué d'appeler votre fucntion dire private MyObject mock; mais un objet réel test,

MyObject test = new MyObject("something", "something else"); 

Appel testStuff() sur mock au lieu de test.

Toutes les instances ne seraient pas automatiquement tournées en dérision, vous devez travailler avec des instances mockées.

+0

testStuff() n'est pas en cause. En fait, je vais le retirer de mon exemple. Le problème est le insert() pendant la construction. Je vais modifier mon exemple pour le clarifier, je l'espère. Cependant, vous dites "Toutes les instances ne seront pas automatiquement mockées", mais dans la documentation il dit: "Si un objet Class est donné [dans le constructeur Expectations] ... toutes les instances de la classe spécifiée seront considérées comme des instances mockées ". Pouvez-vous clarifier votre déclaration? – Didjit

+0

Pointez-moi vers la documentation que vous citez.Comprenez que 'Expectations' une phase d'enregistrement pour les invocations sur des instances mockées. Sa phase de création d'objet non mockée. Objets mockés créés en utilisant 'new MockUp' ou par' Mock' et Ìnjectable' –

+0

Aussi, c'est très déroutant de lire votre code. Vous 'MyObject'définition a seulement un constructeur, 'MyObject (Object obj)' mais dans votre code de test, vous faites, 'new MyObject (" quelque chose "," quelque chose d'autre ");' donc je ne suis pas sûr de ce que je cherche à. Si vos méthodes réelles sont appelées, c'est le cas que vous appelez la méthode sur un objet réel et non un faux. –