Unit testing with Mocks. Testing not performed

I always had a problem when testing modules that call other classes, for example, I have a class that creates a new user from a phone number and then saves it to the database and sends an SMS to the specified number.

Like the code below.

public class UserRegistrationProcess : IUserRegistration { private readonly IRepository _repository; private readonly ISmsService _smsService; public UserRegistrationProcess(IRepository repository, ISmsService smsService) { _repository = repository; _smsService = smsService; } public void Register(string phone) { var user = new User(phone); _repository.Save(user); _smsService.Send(phone, "Welcome", "Message!"); } } 

This is a really simple class, but how would you do it and test it?

I am currently using Mocks, but I don’t like it

  [Test] public void WhenRegistreringANewUser_TheNewUserIsSavedToTheDatabase() { var repository = new Mock<IRepository>(); var smsService = new Mock<ISmsService>(); var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object); var phone = "07012345678"; userRegistration.Register(phone); repository.Verify(x => x.Save(It.Is<User>(user => user.Phone == phone)), Times.Once()); } [Test] public void WhenRegistreringANewUser_ItWillSendANewSms() { var repository = new Mock<IRepository>(); var smsService = new Mock<ISmsService>(); var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object); var phone = "07012345678"; userRegistration.Register(phone); smsService.Verify(x => x.Send(phone, It.IsAny<string>(), It.IsAny<string>()), Times.Once()); } 

Sounds like I'm testing the wrong thing here?

Any thoughts on how to make this better?

+4
source share
3 answers

Refactoring layouts with what @Serghei offers is good.

I also see that the name of the behavior does not actually describe the behavior. I like to use the word "should", as in "My class should do some stuff ".

Your class should not send the user to the database during user registration. It should ask the repository to save the user. All this. He does not know if the repository sends it to the database, saves it in memory or destroys it from orbit. This is not your responsibility for the class.

By formulating behavior in this way, you can clearly show - and help others understand - where your class’s area of ​​responsibility ends.

If you rename your method something like WhenRegisteringANewUser_AsksRepositoryToSaveIt() , which can lead to the fact that your example will become more natural.

+4
source

In your case, no need to write

  repository.Verify(x => x.Save(It.Is<User>(user => user.Phone == phone)), Times.Once()); 

because this method does not return a value you can write

 repository.VerifyAll(); 

Also for smsService, this is a good way to use Moq.

0
source

look after some refactoring

  Mock<IRepository<>> repository; private Mock<ISmsService> smsService; const string phone = "0768524440"; [SetUp] public void SetUp() { repository = new Mock<IRepository<>>(); smsService = new Mock<ISmsService>(); } [Test] public void WhenRegistreringANewUser_TheNewUserIsSavedToTheDatabase() { var userRegistration = new UserRegistrationProcess(repository.Object, smsService.Object); userRegistration.Register(phone); repository.VerifyAll(); smsService.VerifyAll(); } 
0
source

Source: https://habr.com/ru/post/1332869/


All Articles