• 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

Object Storage Arubacloud
+1 głos
512 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 (269,710 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 (269,710 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 892 wizyt
0 głosów
2 odpowiedzi 234 wizyt
0 głosów
2 odpowiedzi 213 wizyt

92,554 zapytań

141,400 odpowiedzi

319,537 komentarzy

61,938 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.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...