web-dev-qa-db-fra.com

Mock un constructeur avec paramètre

J'ai un cours comme ci-dessous:

public class A {
    public A(String test) {
        bla bla bla
    }

    public String check() {
        bla bla bla
    }
}

La logique dans le constructeur A(String test) et check() sont les choses que je cherche à railler. Je veux des appels tels que: new A($$$any string$$$).check() renvoie une chaîne factice "test".

J'ai essayé:

 A a = mock(A.class); 
 when(a.check()).thenReturn("test");

 String test = a.check(); // to this point, everything works. test shows as "tests"

 whenNew(A.class).withArguments(Matchers.anyString()).thenReturn(rk);
 // also tried:
 //whenNew(A.class).withParameterTypes(String.class).withArguments(Matchers.anyString()).thenReturn(rk);

 new A("random string").check();  // this doesn't work

Mais cela ne semble pas fonctionner. new A($$$any string$$$).check() continue de parcourir la logique du constructeur au lieu de rechercher l'objet simulé de A.

73
Shengjie

Le code que vous avez posté fonctionne pour moi avec la dernière version de Mockito et Powermockito. Peut-être que vous n'avez pas préparé A? Essaye ça:

A.Java

public class A {
     private final String test;

    public A(String test) {
        this.test = test;
    }

    public String check() {
        return "checked " + this.test;
    }
}

MockA.Java

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest(A.class)
public class MockA {
    @Test
    public void test_not_mocked() throws Throwable {
        assertThat(new A("random string").check(), equalTo("checked random string"));
    }
    @Test
    public void test_mocked() throws Throwable {
         A a = mock(A.class); 
         when(a.check()).thenReturn("test");
         PowerMockito.whenNew(A.class).withArguments(Mockito.anyString()).thenReturn(a);
         assertThat(new A("random string").check(), equalTo("test"));
    }
}

Les deux tests doivent réussir avec mockito 1.9.0, powermockito 1.4.12 et junit 4.8.2

80
Alban

À ma connaissance, vous ne pouvez pas vous moquer des constructeurs avec mockito, seulement des méthodes. Mais, selon le wiki de la page de code Google de Mockito, il existe un moyen de simuler le comportement du constructeur en créant une méthode dans votre classe qui renvoie une nouvelle instance de cette classe. alors vous pouvez vous moquer de cette méthode. Ci-dessous se trouve un extrait directement du wiki Mockito :

Modèle 1 - utilisation de méthodes sur une ligne pour la création d'objets

Pour utiliser le motif 1 (test d’une classe appelée MyClass), vous devez remplacer un appel tel que

   Foo foo = new Foo( a, b, c );

avec

   Foo foo = makeFoo( a, b, c );

et écrire une méthode d'une ligne

   Foo makeFoo( A a, B b, C c ) { 
        return new Foo( a, b, c );
   }

Il est important de ne pas inclure de logique dans la méthode. juste la ligne qui crée l'objet. La raison en est que la méthode elle-même ne sera jamais testée à l'unité.

Lorsque vous venez tester la classe, l'objet que vous testez sera en fait un espion Mockito, avec cette méthode surchargée, pour renvoyer une maquette. Ce que vous testez n’est donc pas la classe elle-même, mais une version très légèrement modifiée de celle-ci.

Votre classe de test peut contenir des membres tels que

  @Mock private Foo mockFoo;
  private MyClass toTest = spy(new MyClass());

Enfin, dans votre méthode de test, vous simulez l’appel de makeFoo avec une ligne comme

  doReturn( mockFoo )
      .when( toTest )
      .makeFoo( any( A.class ), any( B.class ), any( C.class ));

Vous pouvez utiliser des corrélateurs plus spécifiques que any () si vous souhaitez vérifier les arguments transmis au constructeur.

Si vous souhaitez simplement renvoyer un objet fictif de votre classe, je pense que cela devrait fonctionner pour vous. Dans tous les cas, vous pouvez en savoir plus sur la création d'objets moqueurs ici:

http://code.google.com/p/mockito/wiki/MockingObjectCreation

45
Ben Glasser

Sans utiliser Powermock .... Voir l'exemple ci-dessous, basé sur la réponse de Ben Glasser, car il m'a fallu un certain temps pour le résoudre.

Classe d'origine:

public class AClazz {

    public void updateObject(CClazz cClazzObj) {
        log.debug("Bundler set.");
        cClazzObj.setBundler(new BClazz(cClazzObj, 10));
    } 
}

Classe modifiée:

@Slf4j
public class AClazz {

    public void updateObject(CClazz cClazzObj) {
        log.debug("Bundler set.");
        cClazzObj.setBundler(getBObject(cClazzObj, 10));
    }

    protected BClazz getBObject(CClazz cClazzObj, int i) {
        return new BClazz(cClazzObj, 10);
    }
 }

Classe de test

public class AClazzTest {

    @InjectMocks
    @Spy
    private AClazz aClazzObj;

    @Mock
    private CClazz cClazzObj;

    @Mock
    private BClazz bClassObj;

    @Before
    public void setUp() throws Exception {
        Mockito.doReturn(bClassObj)
               .when(aClazzObj)
               .getBObject(Mockito.eq(cClazzObj), Mockito.anyInt());
    }

    @Test
    public void testConfigStrategy() {
        aClazzObj.updateObject(cClazzObj);

        Mockito.verify(cClazzObj, Mockito.times(1)).setBundler(bClassObj);
    }
}
10
user666

Mockito a des limitations en testant les méthodes finales, statiques et privées.

avec la bibliothèque de tests jMockit, vous pouvez effectuer quelques tâches très facilement et simplement comme ci-dessous:

Constructeur simulé d'une classe Java.io.File:

new MockUp<File>(){
    @Mock
    public void $init(String pathname){
        System.out.println(pathname);
        // or do whatever you want
    }
};
  • le nom du constructeur public doit être remplacé par $ init
  • les arguments et les exceptions jetés restent les mêmes
  • le type de retour doit être défini comme vide

Mock une méthode statique:

  • supprimer les parasites de la signature de méthode
  • la signature de la méthode reste la même sinon
4
Anamika