• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Problem z przetestowaniem metody tworzenia nowego użytkownika

Aruba Cloud - Virtual Private Server VPS
+1 głos
811 wizyt
pytanie zadane 26 stycznia 2022 w Java przez `Krzychuu Stary wyjadacz (13,940 p.)
zamknięte 28 stycznia 2022 przez `Krzychuu

Witam,

Podczas próby przetestowania metody która tworzy nowego użytkownika dostaję błąd

java.lang.NullPointerException: Cannot invoke "org.springframework.security.crypto.password.PasswordEncoder.encode(java.lang.CharSequence)" because the return value of "...service.PasswordHash.encoder()" is null

na google nic nie mogę znaleźć na ten temat, próbowałem to zrobić z mockowaniem i bez ale bez skutku :/

@Service
public class PasswordHash {

    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }
}
public String createUser(User user) {
        if (userRepository.findByEmail(user.getEmail()) != null) {
            throw new BadRequestException("Email has been exists");
        }

        if (userRepository.findByUsername(user.getUsername()) != null) {
            throw new BadRequestException("Username has been exists");
        }

        user.setPassword(passwordHash.encoder().encode(user.getPassword()));

        try {
            userRepository.save(user);

            return user.getUsername();
        } catch (Exception e) {
            throw new BadRequestException(e.getMessage());
        }
    }
@Test
    void should_create_new_user() {
        // given
        when(mockUserRepository.findByEmail(anyString())).thenReturn(null);
        when(mockUserRepository.findByUsername(anyString())).thenReturn(null);
        when(mockPasswordHash.encoder().encode("test")).thenReturn("hashPassword");

        when(mockUserRepository.save(UsersInMemory().iterator().next())).thenReturn(UsersInMemory().iterator().next());

        // when && then
        assertEquals("Username1", userService.createUser(UsersInMemory().iterator().next()));
    }

 

komentarz zamknięcia: Problem rozwiązany

2 odpowiedzi

+2 głosów
odpowiedź 27 stycznia 2022 przez Wiciorny Ekspert (280,450 p.)
wybrane 28 stycznia 2022 przez `Krzychuu
 
Najlepsza

Jak mokujesz w testach swój  sevice?  

Oznaczyłeś klasę jako component- Service, jednak  gdzie z niego korzystasz, czy w wartsiwe repozytorium czy serwisu, mam na myśli w którym miejscu  wykorzystujesz obiekt :
Dodatkowo, gdzie jest  skonfigurowany @Bean którego definiujesz w komponencie @Service ( Generalnie - to jest nieprawidłowe, gdyż Bean powinien znajdować się w @Configuration ), spring nie użyje tego beana.
Więc jeśli na sztywno nie do implementujesz użycia tego beana to dlatego zwraca go null przez kontener

Zdefiniować obiekt poprzez adnotacje @Bean - oznaczyć go fasolką możesz tylko w klasie oznaczonej adnotacją @Configuration- jeśli nie rozbisz zewnętrznej konfiguracji z XML. W ten sposób określasz jaki  obiekt i  w jaki sposób chcemy stworzyć (w twoim przypadku PasswordEncoder). 
Więć coś takiego
 

@Configuration
public class EncoderConfiguration {

    @Bean
    public PasswordEncoder passwordEncoder() {
    
       // w ten sposób funkcja anonimowa 
        return new PasswordEncoder() {
   
            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                return md5Encoder.getMD5Hash(rawPassword.toString()).equals(encodedPassword);
            }
        
            @Override
            public String encode(CharSequence rawPassword) {
                return md5Encoder.getMD5Hash(rawPassword.toString());
            }
        };
    }
} 


To jest definicja, potem na podstawie czegoś takie możesz automatycznie wiązać to do serwisu 
 

@Service
public class PasswordHash() {
        
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    public UserService(PasswordEncoder passwordEncoder) {
        this.passwordEncoder = passwordEncoder;
    }
};

https://docs.spring.io/spring-security/site/docs/4.2.4.RELEASE/apidocs/org/springframework/security/crypto/password/PasswordEncoder.html
PasswordEncoder to interfejs dlatego należy  w tym wypadku jeśli tworzymy ' w loce' funkcje anonimową i tzw obiekt typu interfejsu, należy zaimplementować w locie metody 

komentarz 28 stycznia 2022 przez `Krzychuu Stary wyjadacz (13,940 p.)

Dziękuje za wyjaśnienie działania @Bean, co do problemu to przed Twoją twoją odpowiedzią udało mi się rozwiązać problem. Problemem okazała się klasa PasswordHashService wcześniej wyglądała tak:

@Service
public class PasswordHash {
 
    @Bean
    public PasswordEncoder encoder() {
        return new BCryptPasswordEncoder();
    }
}

teraz wygląda tak:

@Service
@RequiredArgsConstructor
public class PasswordHashService {
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    public String hash(String rawPassword) {
        return bCryptPasswordEncoder.encode(rawPassword);
    }
}

i wszystko działa, domyślam się że nie działało przez to że jak zauważyłeś użyłem @Bean w @Service i w tym był problem

+1 głos
odpowiedź 27 stycznia 2022 przez Adrian89 Początkujący (280 p.)
Hmm... a możesz umieścić więcej informacji? Cały stack z błędem, jak przygotowujesz dane do testów, co jest w UsersInMemory, co jest pod mockUserRepository i mockPasswordHash, jak wyglądają mockowane metody?
komentarz 27 stycznia 2022 przez Wiciorny Ekspert (280,450 p.)
nie potrzeba tyle informacji. mockUserRepository i mockPasswordHash -> to są obiekty mockowane po prostu dla Repozytorium i serwisów :)

Problemem jest tutaj fakt, tego że  metoda PasswordEncoder.encode(...) nie może zostać wywołana, dlatego że

"mockPasswordHash.encoder()" jest nullem, więc albo posiłkujemy się  faktem, że encoder -> zwraca nam obiekt null, albo zły log błędu jest gdyż jeśli mockPasswordHash byłby nullem, to metoda encode by się nie wywoałała na obiekcie null

dodatkowo log z błędu tyczy się service.PasswordHash.encoder() .. więc fakt faktem, brakuje informacji więcej ale nie takich jakie napisałeś
1
komentarz 27 stycznia 2022 przez Adrian89 Początkujący (280 p.)
Słusznie, dzięki za uwagę, że te informacje wiele by nie dały. ;)
komentarz 28 stycznia 2022 przez `Krzychuu Stary wyjadacz (13,940 p.)

Dzięki za odpowiedz następnym razem postaram się dodawać więcej informacji, rozwiązanie problemu podałem w odpowiedzi @Wiciorny

Podobne pytania

0 głosów
3 odpowiedzi 1,214 wizyt
0 głosów
2 odpowiedzi 309 wizyt
0 głosów
2 odpowiedzi 476 wizyt

93,327 zapytań

142,325 odpowiedzi

322,396 komentarzy

62,657 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Wprowadzenie do ITsec, tom 1 Wprowadzenie do ITsec, tom 2

Można już zamawiać dwa tomy książek o ITsec pt. "Wprowadzenie do bezpieczeństwa IT" - mamy dla Was kod: pasja (użyjcie go w koszyku), dzięki któremu uzyskamy aż 15% zniżki! Dziękujemy ekipie Sekuraka za fajny rabat dla naszej Społeczności!

...