stub out a method like an interface using nsubstitute - c#

This is my first post!
I'm trying to write a unit test using nsubstitute but I'm finding the last bit difficult.
I've included a snippet of code below, the test fails when calling the method on the model. Is it possible to stub this method out? Similar to if it was an interface
Cheers guys! Look forward to your responses
James
My unit test attempt
public class MyTests
{
private IModelMapper _modelMapper;
[SetUp]
public void Setup()
{
_modelMapper = Substitute.For<IModelMapper>();
}
[Test]
public void GetModel_Returns_A_Model()
{
var result = theClass.GetModel(new Booking {CurrencyCode = ""}, null);
**UPDATE to include assert**
// Assert
Assert.IsInstance<BasketModel>(result);
}
}
Feature code
public Model GetModel(Booking booking)
{
var model = _modelMapper.Map(booking);
// Is it possible to stub this out? Similar to if it was an interface
model.FormatPricing(somethingHere);
return model;
}
UPDATE - to illustrate return type
BasketModel model = _modelMapper.Map(booking);
UPDATE #2 - to include return
var basketModel = new BasketModel();
BasketModel model = _modelMapper.Map(booking).Returns(basketModel);

Can you include what test failure message you're getting?
Here is the general approach I tend to take for this kind of code. Say we're injecting the IModelMapper into the class-under-test (approximate code; I haven't tested):
[SetUp]
public void Setup()
{
_modelMapper = Substitute.For<IModelMapper>();
theClass = new TheClass(_modelMapper);
}
[Test]
public void GetModel_Returns_Model_From_Mapper()
{
// Arrange
var booking = new Booking { CurrencyCode = "" };
var expectedModel = new BasketModel();
_modelMapper.GetModel(booking).Returns(expectedModel);
// Act
var result = theClass.GetModel(booking, null);
// Assert
Assert.AreSame(expectedModel, result);
}
If you want to stub out BasketModel.FormatModel (that's a big "if". I would recommend using the real type if possible) then you'll want to substitute for BasketModel too.
Be careful - NSubstitute will not work with non-virtual methods, so you may want an interface for BasketModel, or just make sure to use virtual everywhere. (Again, untested code ahead)
[Test]
public void ModelReturnedShouldBeFormatted()
{
// Arrange
var booking = new Booking { CurrencyCode = "" };
var expectedModel = Substitute.For<IBasketModel>();
_modelMapper.GetModel(booking).Returns(expectedModel);
// Act
var result = theClass.GetModel(booking, null);
// Assert
expectedModel.Received().FormatModel(Arg.Any<SomethingHere>());
}
This is testing adherence to a particular contract - TheClass will call FormatModel on the BasketModel returned from the mapper. If you need to duplicate some implementation in the test (again, this is generally discouraged), you can use When..Do:
[Test]
public void FormatModel()
{
// Arrange
var booking = new Booking { CurrencyCode = "" };
var expectedModel = Substitute.For<IBasketModel>();
expectedModel
.When(x => x.FormatModel(Arg.Any<SomethingHere>()))
.Do(/* some action */);
_modelMapper.GetModel(booking).Returns(expectedModel);
// Act
var result = theClass.GetModel(booking, null);
// Assert
// assertion here that depends on "some action" and result
}
Hope this helps.

Related

How to raise an event when unit testing asynchronous method in my case?

I use MS-Test, moq 4.18.2 and FileSystem (System.IO.Abstractions) 17.0.24 for my tests.
I think I wrote a correct test for InfoLoader_LoadInfoAsync. But, I don't understand how to write a test for MyViewModel::StartLoadInfoAsync to check that InfoList was populated correctly. It seems that I have to duplicate instantiation and configuration of InfoLoader as I did in InfoLoader_LoadInfoAsync. Is there a way around this? How such things are usually tested?
public abstract class IInfoLoader
{
public event Action<MyInfo> InfoLoaded;
public abstract Task LoadInfoAsync();
protected void OnInfoLoaded(MyInfo info)
{
InfoLoaded?.Invoke(info);
}
}
public class InfoLoader : IInfoLoader
{
private readonly IFileSystem _fileSystem;
private readonly string _path;
public InfoLoader(string path, IFileSystem fileSystem) {...}
public async override Task LoadInfoAsync()
{
foreach (var data in await _fileSystem.File.ReadAllLinesAsync(_path))
OnInfoLoaded(new MyInfo(...));
}
}
public class MyViewModel
{
private IInfoLoader _infoLoader;
public ObservableCollection<MyInfo> InfoList { get; }
public MyViewModel(IInfoLoader infoLoader) { ... }
public Task StartLoadInfoAsync()
{
_infoLoader.InfoLoaded += (info) => InfoList.Add(info);
return _infoLoader.LoadInfoAsync();
}
}
Tests
[TestMethod]
public async Task InfoLoader_LoadInfoAsync_Success()
{
var path = "...";
var lines = new string[] { "name1", "name2" };
var expectedInfoList = new List<MyInfo>();
foreach(var line in lines)
expectedInfoList.Add(new MyInfo(line));
var fileSystem = new Mock<IFileSystem>();
fileSystem.Setup(fs => fs.File.ReadAllLinesAsync(path, CancellationToken.None))
.ReturnsAsync(lines);
var actualInfoList = new List<MyInfo>();
var infoLoader = new InfoLoader(path, fileSystem.Object);
infoLoader.InfoLoaded += (info) => actualInfoList.Add(info);
await infoLoader.LoadInfoAsync();
// Assert that items in expectedInfoList and actualInfoList are equal
}
[TestMethod]
public async Task MyViewModel_StartLoadInfoAsync_Success()
{
var expectedInfoList = new List<MyInfo>();
// WHAT DO I DO HERE? DO I CREATE AND CONFIGURE infoLoader LIKE in "InfoLoader_LoadInfoAsync" TEST?
var vm = new MyViewModel(infoLoader.Object);
await vm.StartLoadInfoAsync();
actualInfoList = vm.InfoList;
// Assert that items in expectedInfoList and actualInfoList are equal
}
Since the view model depends on the IInfoLoader abstraction, it can be mocked to behave as expected when the desired member is invoked.
Review the comments in the following example
[TestMethod]
public async Task MyViewModel_StartLoadInfoAsync_Success() {
//Arrange
var info = new MyInfo();
List<MyInfo> expectedInfoList = new List<MyInfo>() { info };
// WHAT DO I DO HERE?
var dependency = new Mock<IInfoLoader>(); //mock the dependency
dependency
// When LoadInfoAsync is invoked
.Setup(_ => _.LoadInfoAsync())
// Use callback to raise event passing the custom arguments expected by the event delegate
.Callback(() => dependency.Raise(_ => _.InfoLoaded += null, info))
// Then allow await LoadInfoAsync to complete properly
.Returns(Task.CompletedTask);
MyViewModel subject = new MyViewModel(dependency.Object);
//Act
await subject.StartLoadInfoAsync();
//Assert
List<MyInfo> actualInfoList = subject.InfoList;
actualInfoList.Should().NotBeEmpty()
And.BeEquivalentTo(expectedInfoList); //Using FluentAssertions
}
Note how a Callback is used to capture when LoadInfoAsync is invoked by the subject so that an event can be raised by the mock, allowing the subject under test to flow to completion as desired
Reference MOQ Quickstart: Events
In order to test StartLoadInfoAsync you need an instance of MyViewModel, so you should:
Create this instance.
Invoke the method StartLoadInfoAsync.
Assert that its state is according to what you need.
Now obviously you have a dependency, which is InfoLoader, so you have two options:
Create and configure a new instance of InfoLoader
Mock InfoLoader so you can test MyViewModel independently of InfoLoader.
The second approach is what you may want to follow, this way you do not need to configure again InfoLoader, mock the FileSystem and so on.
You only need to create a mock of InfoLoader and setup its calls, just like you did with the FileSystem.

I need help mocking a method in my c# project

I'm fairly new to this TDD and I'm lost with this at the moment.
I'm trying to use .Setup to get the product by ID of 99 and check it's actually returned in .Returns(saveProduct), which causes me the error below:
enter image description here
What am I doing wrong?
public class ProductControllerTests
{
private Mock<ICart> cartMock;
private Mock<IProductRepository> productRepositoryMock;
private Mock<IOrderRepository> orderRepositoryMock;
private Mock<IProductService> productServiceMock;
private Mock<ILanguageService> languageServiceMock;
private Mock<IStringLocalizer<ProductService>> stringLocalizerMock;
private ProductViewModel product;
private ProductController productController;
public ProductControllerTests()
{
//setup
product = new ProductViewModel();
cartMock = new Mock<ICart>();
productRepositoryMock = new Mock<IProductRepository>();
orderRepositoryMock = new Mock<IOrderRepository>();
stringLocalizerMock = new Mock<IStringLocalizer<ProductService>>();
productServiceMock = new Mock<IProductService>();
languageServiceMock = new Mock<ILanguageService>();
productController = new ProductController(productServiceMock.Object, languageServiceMock.Object);
}
[Fact]
public void CreateValidModelState() // MOCKED
{
// Act
ProductService productService = new ProductService(cartMock.Object, productRepositoryMock.Object, orderRepositoryMock.Object, stringLocalizerMock.Object);
productController = new ProductController(productService, languageServiceMock.Object);
productServiceMock.Setup(x => x.SaveProduct(product)); //It works without this?!? what's it FOR!?
//Arranje
product.Id = 99;
product.Name = "Test box";
product.Description = "The best box ever.";
product.Details = "Toss it and see if it gets back.";
product.Stock = "9000";
product.Price = "9000";
var saveProduct = productController.Create(product);
//productServiceMock.Setup(x => x.GetProductById(It.IsAny<int>())).Returns(saveProduct);
//productServiceMock.SetupGet(x => x.GetProductById(99)).Returns("Test box");
//var expectedProduct = productServiceMock.GetProduct(1);
Assert.IsType<RedirectToActionResult>(saveProduct);
}
}
}
There is a lot of room for improvement in your code snippet.
First, you create private members but then you over write the variable name with local variables.
The idea behind mocking is that when you mock an interface you can Setup its' methods to return whatever you wish them to return. So in your case
productServiceMock.Setup(x => x.GetProductById(99)).Returns(saveProduct);
the line above means that wherever in your controller you have the GetProductById(int) method is called with 99 as a parameter, the method will return the saveProduct object.
You could also write the Setup like
productServiceMock.Setup(x => x.GetProductById(It.IsAny<int>())).Returns(saveProduct);
In this case wherever in your controller the GetProductById() method is called, no matter what is the parameter passed, you will get the saveProductObject.
In this test you have written I can not see any value. What I mean is that create a controller, you create the saveProduct and then you assert it is not null. Of course it is not null, because you populated above.
It would make sense to actually use one of your controllers methods that you know that the GetByUserId() method is used. Then make an assertion upon the return object based on the methods logic.
---Update---
Imagine you have a handler
public class HandlerExample {
private IInjectedService _injectedService;
public HandlerExample(IInjectedService injectedService){
_injectedService = injectedService;
}
public int Handle(testNumber)
{
var serviceResponse = _injectedService.TestMethod(testNumber);
if(serviceResponse)
return 1;
return 2;
}
}
And your interface looks like
public interface IInjectedService
{
bool TestMethod(int testNumber);
}
I won't give any example on the implementation here because it is not relevant. Your test method would then make sense to be like
[Fact]
public void Test()
{
mockedInjectedService = new Mock<IInjectedService>();
mockedInjectedService.Setup(x => x.TestMethod(99)).Returns(true);
var handler = new Handler(mockedInjectedService.Object);
var sut = handler.Handle(99);
Assert.Equal(sut, 1);
}
sut is a convention for "system under test"

How to test method in unit testing

I have such service as below. Let's say i want to test Create() method. I read that in unit testing i should test by comparing, counting and so on. How could i then test my Create() method. Is it ugly to change return type from void Create to bool Create just to be able to check method output for testing purpose or that's not ideal idea? Can you propose something?
public class CreateCarService : ICreateCarService
{
private readonly ICarQuery _carQuery;
private readonly ICarRepository _carRepository;
public CreateCarService(ICarQuery carQuery, ICarRepository carRepository)
{
_carQuery = carQuery;
_carRepository = carRepository;
}
public void Create(Car car)
{
if (car == null) throw new CusException(Error, "Car object cannot be null");
if (_carQuery.IsLoginExist(car.Login))
throw new CusException(Error, "Message1");
if (_carQuery.IsEmailExist(car.Email))
throw new CusException(Error, "Message1");
_carRepository.Add(car);
}
}
You might verify that for any valid Car instance Add method was called only once, by setting up the Moq behavior of IsLoginExist and IsEmailExist method an using a Verify method
[TestFixture]
public class Test
{
[Test]
public void CreateCarServiceTest()
{
var carQueryMock = new Mock<ICarQuery>();
var carRepositoryMock = new Mock<ICarRepository>();
var createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(false);
carQueryMock.Setup(c => c.IsEmailExist(It.IsAny<string>())).Returns(false);
createCarService.Create(new Car());
carRepositoryMock.Verify(c => c.Add(It.IsAny<Car>()), Times.Once);
}
}
It also makes sense to check a negative cases, when Create method throws an exception
[Test]
public void CreateCarNegativeTest()
{
var carQueryMock = new Mock<ICarQuery>();
var carRepositoryMock = new Mock<ICarRepository>();
var createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
Assert.Throws<CusException>(() => createCarService.Create(null));
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(true);
Assert.Throws<CusException>(() => createCarService.Create(new Car()));
carQueryMock.Setup(c => c.IsLoginExist(It.IsAny<string>())).Returns(false);
carQueryMock.Setup(c => c.IsEmailExist(It.IsAny<string>())).Returns(true);
Assert.Throws<CusException>(() => createCarService.Create(new Car()));
}
You can split this method into different tests to have one Assert per test, or pass the parameters to it.
You want to test the "expected behavior" of the member under test. Since the member under test does not return any verifiable output and has a dependency on external abstractions, you should be able to monitor the interaction of the member under test with that external abstractions and verify the expected behavior
One such example
public void CreateCarService_Create_Should_Add_Car() {
//Arrange
Car car = new Car {
Login = "Login",
Email = "Email"
};
ICarQuery carQuery = Mock.Of<ICarQuery>();
ICarRepository carRepository = Mock.Of<ICarRepository>();
ICreateCarService subject = new CreateCarService(carQuery, carRepository);
//Act
subject.Create(car);
//Assert
Mock.Get(carRepository).Verify(_ => _.Add(car), Times.Once);
}
The example above safely navigates through to the end of the member under test but lets say you wanted to test the exception is thrown for the null parameter case.
public void CreateCarService_Create_Should_Throw_CusException_For_Null_Car() {
//Arrange
ICreateCarService subject = new CreateCarService(null, null);
//Act
Action act = ()=> subject.Create(null);
//Assert
var ex = Assert.Throws<CusException>(act);
}
You want to create tests for all the possible paths through the member under test. So take some time and review the subject under test and work out the possible test cases. Arrange the subject to satisfy those cases and exercise those cases to verify the expected behavior.
Reference Moq Quickstart to get a better understanding of how to use the Moq mocking framework.
You don't need to change it to bool, just to test. A simple way you can do this is:
[TestFixture]
public class Test
{
CreateCarService createCarService;
ICarRepository carRepositoryMock;
[Setup]
public void InitializeTest()
{
var carQueryMock = new Mock<ICarQuery>();
carRepositoryMock = new Mock<ICarRepository>();
createCarService = new CreateCarService(carQueryMock.Object, carRepositoryMock.Object);
}
[Test]
public void CreateCarShouldThrowIfNull()
{
//arrange
Car car =null;
//act and assert
Assert.Throw<CustomException>(()=>
{
createCarService.CreateCar(car);
});
}
[Test]
public void CreateCarShouldThrowForInvalidLogin()
{
//arrange
var car = new Car()
{
Login=null,
Email="Email"
};
//act and assert
Assert.Throw<CustomException>(()=>
{
createCarService.CreateCar(car);
});
}
And So on.
You can use Assert.Throw for invalid car objects or Assert.DoesNotThrow for valid car objects. Finally, you can test if the car was added to the repository by:
[Test]
public void CreateCarShouldAddCarToRepo()
{
//arrange
var car = new Car()
{
Login="Login",
Email="Email"
};
//act
createCarService.CreateCar(car);
var carRetrieved =carRepositoryMock.GetCar(car.id);//depending on your implementation
//assert
Assert.AreSame(car,carRetrieved);
}

interaction unit testing using Moq

I have a testing class
public class TerminationRequestValidation : ValidatorBase<TerminationRequest>
{
public TerminationRequestValidation(IIntHR2BLLContext context) : base(context)
{
}
public override ValidationResult ValidateWithoutThrow(TerminationRequest request)
{
var result = ValidationResult.Success;
/* some logic */
var isHRIAdvanced = Context.Logics.Accessible.HasAccess(request, IntHRSecurityOperationCode.TerminationRequestSetTerminationDateBehindhand);
if (!isHRIAdvanced && Context.Logics.Termination.IsTerminationDateChanged(request))
{
result += CheckTerminationDate(request);
}
return result;
}
public virtual ValidationResult CheckTerminationDate(TerminationRequest request)
{
var result = ValidationResult.Success;
/* any validation logic */
return result;
}
}
I need to check 'CheckTerminationDate' method is performed
[TestMethod]
public void Validate_TerminationDateChangedbyNotAdvanced_TerminationDateCheck()
{
var context = FakeContext.Create();
// first stub
var accessibleBllStub = new Mock<IAccessibleBLL>(MockBehavior.Loose);
accessibleBllStub.Setup(z => z.HasAccess(It.IsAny<TerminationRequest>(), It.IsAny<IntHRSecurityOperationCode>()))
.Returns<TerminationRequest, IntHRSecurityOperationCode>((x, y) => y != IntHRSecurityOperationCode.TerminationRequestSetTerminationDateBehindhand);
context.StubBLL(z => z.Accessible, accessibleBllStub.Object);
// second stub
var terminationBLLStub = new Mock<ITerminationBLL>(MockBehavior.Loose);
terminationBLLStub.Setup(z => z.IsTerminationDateChanged(It.IsAny<TerminationRequest>())).Returns(true);
context.StubBLL(z => z.Termination, terminationBLLStub.Object);
// mock
var validator = new Mock<TerminationRequestValidation>(MockBehavior.Loose, context.MainContext);
// act
validator.Object.ValidateWithoutThrow(termination);
//assert
validator.Verify(z => z.CheckTerminationDate(It.IsAny<TerminationRequest>()));
}
This unit test off course isn't work. On the one hand I need to call real 'ValidateWithoutThrow' method, on the another hand I need to check that stub method 'CheckTerminationDate' is performed.
Guys, help me to find the best solution! May be I need to redesign testing class to make in more testable
I need to check 'CheckTerminationDate' method is performed
You don't. You need to test that the request was validated. Whether that's done inline, or by calling CheckTerminationDate, or by calling some other method, that's an implementation detail - and unit tests don't care about that.
So, your tests should look something like this:
public void ValidateWithoutThrow_ReturnsSucessfulResult_When_RequestIsValid()
{
var validRequest = //...
var validator = new TerminationRequestValidation(/*...*/); // don't mock this class
var result = validator.TerminationRequestValidation(validRequest);
Assert.Equal(ValidationResult.Success, result);
}
public void ValidateWithoutThrow_ReturnsUnsucessfulResult_When_RequestIsInvalid()
{
var invalidRequest = //...
var validator = new TerminationRequestValidation(/*...*/); // don't mock this class
var result = validator.TerminationRequestValidation(invalidRequest);
Assert.NotEqual(ValidationResult.Success, result);
}
As a general rule of thumb, avoid verifying how the method works internally. You're coupling your tests to implementation details and refactoring/maintaining those details will be a living hell.

Should I unit test multiple (different) input values to a function?

Give the following function:
public class UnderTest
{
public bool Foo(Bar input)
{
if(input.State != State.Paid)
throw new Exception();
return true;
}
}
Whats the best way to test input.State != State.Paid given that State is an enum? I came up with the following. However, this will not catch if a new enum value is added. Is there a better way to test this or should I only care about a single test?
[Theory]
[InlineData(State.New)]
[InlineData(State.Cancelled)]
[InlineData(State.Complete)]
public void NotPaidBar_ThrowsException(State state)
{
// Arrange
var bar = new Bar()
{
State = state
};
var underTest = new UnderTest();
// Act
Action result = () => underTest.Foo(bar);
// Assert
result
.ShouldThrow<Exception>();
}
It is important to consider that unit-tests will not ensure that your program is correct, but only that it isn't broken as per your definitions.
As for your particular question, if you're using TDD with triangulation, and if you stumble upon a new test that doesn't force you to write any new production code, then I would feel that the extra test is not useful from a productivity standpoint.
You can test all the states with a simple loop if you want to, even those that would be added later to the enum:
public void NotPaidBar_ThrowsException()
{
var allStates = Enum.GetValues(typeof (State)).Cast<State>();
foreach (var state in allStates.Except(new[]{State.Paid}))
{
// Arrange
var bar = new Bar()
{
State = state
};
var underTest = new UnderTest();
// Act
Action result = () => underTest.Foo(bar);
// Assert
result.ShouldThrow<Exception>();
}
}

Categories

Resources