Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SpringBoot: Testing the Service layer

Let's assume that I have two classes:

  1. TodoRepository
  2. TodoService

the TodoRepository is a simple CRUD Repository:

public interface TodoRepository extends CrudRepository<T, ID> {
}

the TodoService is just a class which calls this Repository:

@Service
public class TodoService{

    private final TodoRepository todoRepository;

    @Autowired
    public TodoService(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    public void createTodo(Todo todo) {
        todoRepository.save(todo);
    }
}

Should I bother testing the service layer?

Edit:

Thanks to the explanation from @Dherik. I created a test class which looks like:

Note: I am using JUnit5, Mockito and Spring framework

@ExtendWith(SpringExtension.class)
class TodoServiceTest {

    @MockBean
    private TodoRepository todoRepository;

    private TodoService todoService;

    @BeforeEach
    void setUp() {
        todoService = new TodoService(todoRepository);
    }

    @AfterEach
    void tearDown() {
        clearInvocations(tanklevelRepository);
    }

    @Test
    public void createTodo() {
        todoService.createTodo(new Todo());

        // verify if the save method is called when createTodo is called too
        verify(todoRepository, times(1)).save(any(Todo.class));
    }
}
like image 755
stergipe Avatar asked Nov 30 '18 15:11

stergipe


2 Answers

Yes, it's important.

Even now being a very simple class, maybe some developer on the future could add some weird condition on this method createTodo that the Todo is not saved anymore.

If you write a test for the actual method to verify if the save is called, the developer will be advised about the situation if he makes some change that affect the Todo save.

See a pseudo test example:

@Test
public void createTodo() {

    TodoRepository todoRepository = mock(TodoRepository.class);

    TodoService todoService = new TodoService(todoRepository);
    todoService.createTodo(new Todo());
    
    // verify if the save method is called when createTodo is called too
    verify(todoRepository, times(1)).save(any(Todo.class));

}
like image 99
Dherik Avatar answered Sep 28 '22 00:09

Dherik


I've seen this kind of thing tested with Junit using a Mock framework and injecting a mock repo into the service, then checking the mock repo was called. That seems really pointless to me as the test knows too much about the implementation. If you change the implementation you have to rewrite the test, so it's no use for refactoring.

I would test this kind of thing with an integration test that treated the app like a black box. i.e. start the app, trigger whatever creates a todo and check that it was created. I'd probably use cucumber-jvm and have a scenario with a step to create a todo and another to retrieve it.

I think you should create tests that

  • help you write reliable code
  • allow refactoring without the need to rewrite tests
  • prove the application does what it's supposed to
like image 35
pcoates Avatar answered Sep 28 '22 00:09

pcoates