44 votes

auto-câblage de spring 3 et tests junit

Mon code :

@Component
public class A {
    @Autowired
    private B b;

    public void method() {}
}

public interface X {...}

@Component
public class B implements X {
    ...
}

Je veux tester en classe d'isolation A. Dois-je simuler la classe B ? Si oui, comment ? Parce qu'elle est autowired et il n'y a pas de setter où je pourrais envoyer l'objet fantaisie.

83voto

James Points 5907

Je veux tester en classe d'isolement A.

Vous devez absolument simuler B, plutôt que d'instancier et d'injecter une instance de B. Le but est de tester A, que B fonctionne ou non, et vous ne devez donc pas laisser un B potentiellement cassé interférer avec le test de A.

Cela dit, je recommande vivement Mockito . En ce qui concerne les frameworks de simulacre, il est extrêmement facile à utiliser. Vous pouvez écrire quelque chose comme ce qui suit :

@Test
public void testA() {
    A a = new A();
    B b = Mockito.mock(B.class); // create a mock of B
    Mockito.when(b.getMeaningOfLife()).thenReturn(42); // define mocked behavior of b
    ReflectionTestUtils.setField(a, "b", b); // inject b into the B attribute of A

    a.method();

    // call whatever asserts you need here
}

18voto

Mike Partridge Points 1438

Voici un exemple de la façon dont j'ai fait fonctionner mes tests avec Spring 3.1, JUnit 4.7 et Mockito 1.9 :

FooService.java

public class FooService {
    @Autowired private FooDAO fooDAO;
    public Foo find(Long id) {
        return fooDAO.findById(id);
    }
}

FooDAO.java

public class FooDAO {
    public Foo findById(Long id) {
        /* implementation */
    }
}

FooServiceTest.java

@RunWith(MockitoJUnitRunner.class)
public class FooServiceTest {
    @Mock private FooDAO mockFooDAO;
    @InjectMocks private FooService fooService = new FooService();

    @Test public final void findAll() {
        Foo foo = new Foo(1L);
        when(mockFooDAO.findById(foo.getId()).thenReturn(foo);

        Foo found = fooService.findById(foo.getId());
        assertEquals(foo, found);
    }
}

15voto

Jeff Storey Points 22103

Vous pouvez injecter le champ par réflexion à l'aide de la méthode Spring ReflectionTestUtils.setField (ou l'extension junit PrivateAccessor ) ou vous pouvez créer un contexte d'application fantaisie et le charger. Bien que pour un simple test unitaire (sans intégration), je préfère utiliser la réflexion pour plus de simplicité.

0voto

Aaron Points 395

Ce forum de discussion ça me paraît logique. Vous pouvez déclarer votre membre privé b comme un type d'InterfaceB qui est implémenté par la classe B (c'est-à-dire : orienté service) puis déclarer une classe MockB qui implémenterait également la même interface. Dans votre contexte d'application en environnement de test, vous déclarez la classe MockB et dans votre contexte d'application de production, vous déclarez la classe B normale et dans les deux cas, le code de la classe A n'a pas besoin d'être modifié puisqu'il sera auto-connecté.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X