2015-08-29 6 views
11

Quindi ho cercato di capirlo da solo tramite documentazione, ma non riesco ad arrivare da nessuna parte.Guice, DI e test di unità in gioco 2.4

Ho alcune semplici impostazioni di binding DI in una classe di servizio che crea un oggetto repository. Semplice. Tuttavia, quando eseguo questo in modalità test, @Inject non fa nulla e l'oggetto repository non viene mai istanziato.

@Inject 
TagRepository tagRepository; 

Così sulla linea in cui il suo uso, in modalità di prova, abbiamo naturalmente ottenere un NullPointerException

tagRepository.tagExistsByName(tag); 

Questa bolle su nel mio test in questo modo:

[error] Test services.TagsServiceTest.testAddNewTag failed: java.lang.NullPointerException: null, took 0.097 sec 
[error]  at services.TagService.tagExists(TagService.java:27) 
[error]  at services.TagService.addNewTag(TagService.java:18) 
[error]  at services.TagsServiceTest.testAddNewTag(TagsServiceTest.java:29) 

La mia domanda è, come posso configurare la mia applicazione per utilizzare gli iniettori Guice in modalità test? Non avevo questo problema con i miei controller perché le richieste venivano effettivamente fatte a loro, impostando l'applicazione completa.

Una cosa che dovrei menzionare è che sto usando un provider per fornire la mia app ai test. Dovrei usare il costruttore di applicazioni Guice? Se è così, dove va? I documenti di gioco non sono molto utili a tale riguardo. Qui è il fornitore

@Override 
protected FakeApplication provideFakeApplication() { 
    return new FakeApplication(new java.io.File("."), Helpers.class.getClassLoader(), ImmutableMap.of("play.http.router", "router.Routes"), new ArrayList<String>(), null); 
} 

UPDATE:

Ecco l'aggiornamento basato su suggerimento di sotto

Dentro la mia classe BaseTest

@Override 
    protected Application provideApplication() { 
     return new GuiceApplicationBuilder().in(Mode.TEST).build(); 
    } 

E poi nella classe di test di servizio

@Before 
    public void beforeTest() { 
     Injector injector = new GuiceInjectorBuilder().bindings(bind(TagService.class).toInstance(new TagService())).injector(); 
     tagService = injector.instanceOf(TagService.class); 
    } 

Tuttavia, sto ancora ricevendo eccezioni del puntatore nullo perché TagRepository non viene iniettato.

RISPOSTA:

Stavo pensando a questo un po 'sbagliato. Se si imposta l'iniettore con l'oggetto è necessario iniettare, quindi creare un'istanza da quello, non riceverai più NullPointerExceptions

@Before 
public void beforeTest() { 
    Injector injector = new GuiceInjectorBuilder().bindings(bind(TagRepository.class).toInstance(new TagRepository())).injector(); 
    tagService = injector.instanceOf(TagService.class); 
} 
+0

Penso che si dimentichi di creare il mock del repository '@ Injected' ed è per questo che si ottiene l'eccezione. –

+0

Quale sarebbe il modo corretto di creare quel finto essere? Costruttore di applicazioni? Se sì, dove andrebbe? – Zarathuztra

+0

Se si sta usando il constructor o il parametro injection, sarebbe abbastanza facile, ma da quello che hai fornito suppongo che tu non ne usi nessuno, quindi dai un'occhiata a questa discussione http://stackoverflow.com/questions/2448013/ how-test-guice-inections –

risposta

6

Se stai estendendo WithApplication, è possibile ignorare protected Application provideApplication() per restituire un Application costruito usando GuiceApplicationBuilder.

Ad esempio (basato su this code) è possibile creare l'app, aggiungere o sovrascrivere i collegamenti, ecc. E impostare la modalità. Se si effettua l'abstract della classe, funzionerà automaticamente con tutte le classi figlie.

public abstract class AbstractFakeApplicationTest extends WithApplication 
{ 
    private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFakeApplicationTest.class); 

    @Override 
    protected Application provideApplication() 
    { 
     return new GuiceApplicationBuilder().in(Mode.TEST) 
              .build(); 
    } 

    @Override 
    public void startPlay() 
    { 
     super.startPlay(); 
     // mock or otherwise provide a context 
     Http.Context.current.set(new Http.Context(1L, 
                Mockito.mock(RequestHeader.class), 
                Mockito.mock(Http.Request.class), 
                Collections.<String, String>emptyMap(), 
                Collections.<String, String>emptyMap(), 
                Collections.<String, Object>emptyMap())); 
    } 

    public Http.Context context() 
    { 
     return Http.Context.current.get(); 
    } 
} 

classi figlie poi basta estendere questa classe e test come normale - tutte DI dovrebbero verificarsi come avviene quando si esegue l'applicazione normalmente.

È possibile vedere vari esempi di esso here

Questo dà la struttura di base per quello che devi fare. Speriamo che i documenti a https://playframework.com/documentation/2.4.x/JavaTestingWithGuice abbiano un po 'più senso ora.

+0

Questo è ESATTAMENTE quello che stavo cercando. Lo farò un colpo stasera e vedrò cosa succede – Zarathuztra

+0

Ho provato questo e sta ancora lanciando NullPointerException. Incollato il mio codice nella mia domanda. Ho seguito gli esempi che mi hai dato e ho combinato ciò che c'è nei documenti Play, ma non riesco ancora a far funzionare correttamente l'iniettore. – Zarathuztra

+1

Non importa, ho capito che devo legare l'oggetto del repository iniettato all'iniettore, quindi creare un oggetto TagService da quello. Mi hai indicato lungo la strada giusta, grazie mille! – Zarathuztra