web-dev-qa-db-fra.com

câblage automatique du printemps 3 et test de la jonction

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'isolement A. Dois-je me moquer de la classe B? Si oui, comment? Parce qu'il est câblé automatiquement et qu'il n'y a pas de setter où je pourrais envoyer l'objet moqué.

44
mike27

Je veux tester en classe d'isolement A.

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

Cela dit, je recommande fortement Mockito . Au fur et à mesure que les frameworks se moquent, il est extrêmement facile à utiliser. Vous écririez quelque chose comme ceci:

@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
}
83
earldouglas

Voici un exemple de la façon dont mes tests ont fonctionné 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);
    }
}
18
Mike Partridge

Vous pouvez injecter le champ via la réflexion en utilisant le ReflectionTestUtils.setField De Spring (ou l'extension junit PrivateAccessor) ou vous pouvez créer un contexte d'application simulé et le charger. Bien que pour un test unitaire simple (non-intégration), je préfère utiliser la réflexion pour plus de simplicité.

15
Jeff Storey

Cette discussion sur le forum est logique pour moi. 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 qu'une classe MockB implémenterait également la même interface. Dans votre contexte d'application d'environnement de test, vous déclarez la classe MockB et 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é car il sera câblé automatiquement.

0
Aaron