#Trying to understand Mockito (Spring Boot)

1 messages · Page 1 of 1 (latest)

cosmic shadow
#

I am currently trying to test my Service layer in my Spring project. But for that I have to use Mockito. I understand the basic concept of Mockito, which is "faking" dependencies of a class. The thing I don't understand about Mockito is the methods (for example:when()) and how to use these methods. And I can't find a explanation of them either. I read:

Sakuga Webflow template is highly suitable for creating websites for startups, apps, software, SaaS, and technology businesses.

HowToDoInJava

Spring boot mockito test service layer example. Learn to write unit tests for service layer of Spring application using JUnit and Mockito frameworks.

Spring Boot Tutorial

1 MILLION learners learning Programming, Cloud and DevOps. Check out our roadmaps!

Medium

Introduction

burnt frigateBOT
#

<@&1004656351647117403> please have a look, thanks.

burnt frigateBOT
#

While you are waiting for getting help, here are some tips to improve your experience:

Code is much easier to read if posted with syntax highlighting and proper formatting.

If nobody is calling back, that usually means that your question was not well asked and hence nobody feels confident enough answering. Try to use your time to elaborate, provide details, context, more code, examples and maybe some screenshots. With enough info, someone knows the answer for sure.

Don't forget to close your thread using the command </help-thread close:1027500463647621170> when your question has been answered, thanks.

tough mist
#

i can construct u some simple, but a bit contrived example:

#
class FileReader {
  private String name;
  FileReader(String name) { this.name = name; }
  String read() { return Files.readString(Path.of(name)); }
}

class Foo {
  static boolean checkHello(FileReader reader) { reader.read().equals("Hello World"); }
}
#

usage example:

#
System.out.println(Foo.checkHello(new FileReader("foo.txt")));
#

this would now print true or false, depending on whether foo.txt contains Hello World

#

now we want to test this class

#

and the test obviously shouldnt read an actual file

#

so we have to mock FileReader

#
@Test
void canCheckHello() {
  FileReader helloFile = mock(FileReader.class);
  when(helloFile.read()).thenReturn("Hello World");

  FileReader nonHelloFile = mock(FileReader.class);
  when(nonHelloFile.read()).thenReturn("abc");

  assertTrue(Foo.checkHello(helloFile));
  assertFalse(Foo.checkHello(nonHelloFile));
}
#

now, the Foo.checkHello executes on a fake FileReader for which we mocked the read() method to directly return a given string

#

instead of reading actual files

#

so the test can execute without reading files

cosmic shadow
# tough mist ```java @Test void canCheckHello() { FileReader helloFile = mock(FileReader.cl...

Okay thank you very much, that is an understandable example. I still don't fully understand how you would use it in certain scenarios. For example, this is my test: java @Test public void loadUserByUsername() { Verwaltung verwaltung = new Verwaltung( "test", "[email protected]", "test", Rolle.getPrefixedRolle(Rolle.VERWALTUNG) ); UserDetailsImpl userDetailsExpected = new UserDetailsImpl(verwaltung); // when(userRepository.findByEmail("[email protected]")).thenReturn(Optional.of(verwaltung)); ? UserDetailsImpl userDetails = userDetailsService.loadUserByUsername("[email protected]"); assertEquals(userDetailsExpected, userDetails); } I am not sure where I should use Mockito methods here and why. And also, if I would do something like this: java when(userDetailsService.loadUserByUsername("[email protected]")).thenReturn(userDetails);couldn't I just "fake" the functionality of the method and so fake the whole test/make this whole test pointless?

burnt frigateBOT
tough mist
#

whats the method u want to test?

#

userDetailsService.loadUserByUsername?

#

then u need to construct a real instance of that service

#

but the service likely wants some parameters

#

a database for example

#

and thats what u mock

#

not the service

#

its dependencies

cosmic shadow
# tough mist `userDetailsService.loadUserByUsername`?

Yes, sorry ```java
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
private final UserRepository userRepository;
public UserDetailsServiceImpl(UserRepository userRepository) {
this.userRepository = userRepository;
}
@Override
public UserDetailsImpl loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userRepository.findByEmail(email)
.orElseThrow(() -> new UsernameNotFoundException("User with email " + email + " not found!"));
return new UserDetailsImpl(user);
}
}

burnt frigateBOT
tough mist
#

yeah. so u want to create an instance of this class

#

and it wants a repo from u

#

the repo, u want to mock

#

cause u dont want to test userRepository.findByEmail(email)

#

u want to test the rest

#

so

#
// GIVEN a repo with a user
User user = mock(User.class);
UserRepository repository = mock(UserRepository.class);
when(repository.findByEmail(any()).thenReturn(Optional.of(user));

// WHEN searching that user
UserDetailsService service = new UserDetailsServiceImpl(repository);
UserDetailsImpl details = service.loadUserByUsername("[email protected]");

// THEN found that user
assertEquals(details.getUser(), user);
#

and another one for not finding it:

#
// GIVEN a repo with no users
UserRepository repository = mock(UserRepository.class);
when(repository.findByEmail(any()).thenReturn(Optional.empty());

// WHEN searching a user
UserDetailsService service = new UserDetailsServiceImpl(repository);
Executable searchUser = () -> service.loadUserByUsername("[email protected]");

// THEN did not find the user
assertThrows(UsernameNotFoundException.class, searchUser);
#

now u tested the service independently of the repo

cosmic shadow
#

Okay, so I also have to mock the user? And in this line java when(repository.findByEmail(any()).thenReturn(Optional.of(user)); shouldn't I have to specify the email which returns the user? Because the user is a mock it doesn't have a email or anything so how can I determine if the email returns the correct user if I use any()? Or is it because I alreay tested my repo it shouldn't be involved in this in any way and you just fake the db retrieval because my tests for the repo class already passed?

tough mist
#

u dont have to mock the user. but it doesnt serve any point to create it

#

since the method doesnt work with the user (yet)

#

so might as well just go the lazy way and mock it

#

if its easy for u to create users, u can create a real one. it doesnt matter

#

shouldn't I have to specify the email which returns the user?
it doesnt matter. the email-searching is not part of the loadUserByUsername method. its not part of ur test. the email-searching is part of the repo and the repo u test elsewhere, not in this unit test

#

unit tests have to focus on the method they want to test

#

its called unit test

#

not test

#

the unit in this case is this particular method and nothing else

#

Or is it because I alreay tested my repo it shouldn't be involved in this in any way and you just fake the db retrieval because my tests for the repo class already passed?
exactly

cosmic shadow
#

Okay thank you very much. I wasn't exactly sure what I all had to mock. It's pretty weird to "simulate" / "fake" everything to just test a method. Definitly have to get used to that with Mockito. Still, thanks for your simple answers and showcasing how to simulate both scenarios (with and without users in db)

tough mist
#

cat_thumbs_up
in general, its preferred to create real objects when possible

#

but sometimes its either extremely complicated, cause those test objects would need a super big and sophhisticated setup

#

or they involve things u just dont want, like real file IO

#

mockito is a "lazy" and easy way out

#

enabling u to create fake objects extremely quick

#

its just a bit fragile, cause if someone changes the code of the method under test, it can easily happen that the tests fail bc the method now uses sth from the mock that wasnt mocked yet

#

like, what if in the future ur service is changed to do sth on the users email

#

then the test fails, bc user.getEmail() wasnt mocked yet

#

a real object doesnt have that issue

cosmic shadow
#

Okay and how or when do you decide to use a mock or a real object then? If there are too much dependencies you would all have to autowire and create objects for etc.?

tough mist
#

if the objects are simple to create and they dont do anything that shouldnt be done in a test (real IO, taking long ...), prefer to create a real object

#

for example, User might be easy to create real

#

but UserRepository is probably not

#

dont create fake classes

#

like UserRepositoryTestImpl

#

thats like using mockito, but much more ugly

#

might as well use mockito then

#

but if u can create the real object easily, u can do that

cosmic shadow
#

Oh okay, yeah thanks. Ig in this case I then use Mockito because I already tested all the repos and its really the only dependency I have for most of my services so it should be good, thank you very much