Spring nadpisanie beana w testach

0

Witam problem jest następujący: Mam klasę @Configuration w której tworzę sobie beana, który odpowiada mi za połączenie do bazy - nie jest to JPA ani NoSQL. Teraz che napisać sobie test integracyjny i w teście potrzebuję dostarczyć innej definicji tego beana. Nie wiem jak to zrobić ponieważ:

@TestConfiguration nie zadziała, ponieważ nadal zostaną powołane dwie instancje tego beana - zwykła i testowa - i po prostu do testów będzie chciał użyć tej testowej, ale wcześniej poleci Exception w stylu Instance already exists

@Primary - identyczna sytuacja, ten sam exception

@Profile("!test") na beanie nie-testowym i @ActiveProfile("test") w teście działa tak jak chce, ale nie chce/nie mogę w tym wypadku korzystać z profili.

Czy jest jakiś inny sposób żeby to wykonać?

2

Albo sam składasz obiekty do testów jednostkowych albo profile albo spring.main.allow-bean-definition-overriding=true

0
Charles_Ray napisał(a):

spring.main.allow-bean-definition-overriding=true

To mi może zrobić trochę bałagan w projekcie i ponadpisywać również te których nie chce nadpisywać.

2

Spróbuj utworzyć metodę fabryczną w klasie @Configuration, bez żadnych adnotacji zwracającą instancję tego beana.
Potem w testach zrób: new ConfigurationClass().getConnection();
W metodzie getConnection() umieść implementację tworzącą obiekt do celów testowych.

0
dawid.wiklo4 napisał(a):

Spróbuj utworzyć metodę fabryczną w klasie @Configuration, bez żadnych adnotacji zwracającą instancję tego beana.
Potem w testach zrób: new ConfigurationClass().getConnection();
W metodzie getConnection() umieść implementację tworzącą obiekt do celów testowych.

To może być dobre, ale jak go będę powoływał do życia w czasie działania apki (w nie-testach)?

0
anckor napisał(a):
dawid.wiklo4 napisał(a):

Spróbuj utworzyć metodę fabryczną w klasie @Configuration, bez żadnych adnotacji zwracającą instancję tego beana.
Potem w testach zrób: new ConfigurationClass().getConnection();
W metodzie getConnection() umieść implementację tworzącą obiekt do celów testowych.

To może być dobre, ale jak go będę powoływał do życia w czasie działania apki (w nie-testach)?

Coś takiego jak poniżej, w czasie działania aplikacji z tego co zrozumiałem nie potrzebujesz tej instancji.
Metoda bez adnotacji @Bean nie utworzy obiektu.

    @Bean
    EntityManager getEntityManager() {
        EntityManagerFactory entityManagerFactory = Persistence
                .createEntityManagerFactory("persistence-unit");
        return entityManagerFactory.createEntityManager();
    }

    EntityManager getTestEntityManager() {
        EntityManagerFactory entityManagerFactory = Persistence
                .createEntityManagerFactory("test-persistence-unit");
        return entityManagerFactory.createEntityManager();
    }
0

Coś takiego jak poniżej, w czasie działania aplikacji z tego co zrozumiałem nie potrzebujesz tej instancji.

Właśnie w czasie działania apki potrzebuję tego beana. A w teście potrzebuje testowej wersji tego beana (tylko i wyłącznie, bo gdy będzie próbował powołać do życia oba, to leci exception). Generalnie chce osiągnąć taki rezultat jak opisałem w pierwszym poście z @Profile, tylko że nie bez @Profile. Może właśnie jakaś fabryka.

2

Możesz zrobić sobie taką konfigurację:

@Configuration
class AppConfiguration {
   @Bean
   MyService myService(MyRepository myRepository) {
      return new MyService(myRepository);
   }

   @Bean
   MyRepository myRepository() {
      return new MySQLRepository();
   }
}

Produkcyjnie działa wiadomo jak. Natomiast w testach jednostkowych na luzie robisz sobie:

MyInMemoryRepository myInMemoryRepository = new MyInMemoryRepository();
MyService objectUnderTest = new AppConfiguration().myService(myInMemoryRepository);

Możesz to schować za jakąś statyczną metodą fabrykującą, whatever - ważne, żeby zawołać produkcyjne AppConfiguration#myService.

2
  1. Nie rób tego w ogóle. Odpal w teście bazę in-memory, jakieś h2 czy hsql (a ustawienia bazy są w properties, więc w test properties masz takie które pokazują na to testowe h2) i na niej pracuj. Po co potrzebujesz podmieniać obiekt łączący się z bazą? o_O Jedyna sytuacja kiedy coś takiego potrzebowałem to kiedy chciałem koniecznie przetestować corner case, że połaczenie do bazy działa a potem nagle umiera i rzuca jakiś wyjątek. To sie trudno symuluje na prawdziwej bazie in memory i wtedy zrobiłem tak jak w punkcie 2, ale to jeden jedyny taki test.
  2. Mozesz użyć profili springowych
  3. Mozesz też zrobić to "na janusza", tzn w teście wstrzyknac sobie obiekt który używa tego czegoś co chcesz podmienić, następnie zrobić po prostu Whitebox.setInternalState(serwis, Klasa.class, mockowyObiekt); a potem po teście sobie to przywrócić ;]

1 użytkowników online, w tym zalogowanych: 0, gości: 1