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);
}
Related
I'm using AutoFixture to create a service which has a repository dependency injected through the constructor. When using fixture.Create<>, a mock repository is automatically provided for the dependency. I'd like to use CallBase on the mock repository so that it calls the method on the actual underlying class. Is this possible? The methods are defined as virtual so that Moq can override them. Below is a basic example and a test with AutoFixture which fails. Then the same test is shown using Moq directly which succeeds. The testing library being used is xUnit. Assume the interfaces have the shown methods defined.
Service:
public class PersonService : IPersonService {
private readonly IPersonRepository _personRepository;
public PersonService(IPersonRepository personRepository) {
_personRepository = personRepository;
}
public virtual string GetPersonName(int id) => _personRepository.GetPersonName(id);
}
Repository:
public class PersonRepository : IPersonRepository {
public virtual string GetPersonName(int id) => Data.People[id].FirstName!;
}
Data:
public static class Data {
public static List<Person> People { get; } = new() {
new Person { FirstName = "Jack" },
new Person { FirstName = "Jill" }
};
}
Person:
public class Person {
public string? FirstName { get; set; }
}
Failing Test with AutoFixture: result is null, the GetPersonName method on the repo is never called via CallBase
[Fact]
public void AutoFixture_Test_CallBase() {
var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization());
var mockPersonRepository = fixture.Freeze<Mock<PersonRepository>>();
mockPersonRepository.Setup(r => r.GetPersonName(It.IsAny<int>())).CallBase();
var sut = fixture.Create<PersonService>();
var result = sut.GetPersonName(1);
Assert.Equal(Data.People[1].FirstName, result);
}
The same test works fine using Moq without AutoFixture:
[Fact]
public void Moq_Test_CallBase() {
var mockPersonRepository = new Mock<PersonRepository>();
mockPersonRepository.Setup(r => r.GetPersonName(It.IsAny<int>())).CallBase();
var sut = new PersonService(mockPersonRepository.Object);
var result = sut.GetPersonName(1);
Assert.Equal(Data.People[1].FirstName, result);
}
The problem is that when PersonService is created by AutoFixture, it uses the Mock<IPersonRepository> to build up an IPersonRepository but in your code it is not defined so it uses the default.
Since you want to setup the Mock<IPersonRepository> with CallBase, one approach would be to freeze a Mock<PersonRepository> and then, whenever an IPersonRepository is required by AutoFixture to build up any other object that depends on it (like the PersonService) you call fixture.Create<PersonRepository>()
So it'd be like this:
[Fact]
public void AutoFixture_Test_CallBase()
{
var fixture = new Fixture();
fixture.Customize(new AutoMoqCustomization());
var mockPersonRepository = fixture.Freeze<Mock<PersonRepository>>();
mockPersonRepository
.Setup(r => r.GetPersonName(It.IsAny<int>()))
.CallBase();
fixture.Register<IPersonRepository>(() => fixture.Create<PersonRepository>());
var sut = fixture.Create<PersonService>();
var result = sut.GetPersonName(1);
Assert.Equal(Data.People[1].FirstName, result);
}
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 ran into a failing unit test in a complex piece of code and the Moq logging wasn't doing it for me. I need to know what's different between what I expected a method to be called with and what it was actually called with. I ended up attaching a debugger to the unit test and that way I could look into the object being passed to the moq and manually compare all its values. All this effort would not be neccesary if I got more information from the Verify error message.
How do I log the differences between these two things?
What I expected the mocked method to be called with
What the mocked method was actually called with
A simplified example:
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
namespace MyNamespace
{
[TestClass]
public class MyTestClass
{
[TestMethod]
public void MyTestMethod()
{
// Arrange
var serviceMock = new Mock<IService>();
var model = new Model
{
Word = "Foo",
Number = 1
};
var servicecaller = new ServiceCaller(serviceMock.Object);
// Act
servicecaller.CallService(model);
// Assert
serviceMock.Verify(mock =>
mock.Call(
It.Is<Model>(m =>
m.Word == "Bar"
&& m.Number == 1)));
}
}
public class ServiceCaller
{
private IService _service;
public ServiceCaller(IService service)
{
_service = service;
}
public void CallService(Model model)
{
_service.Call(model);
}
}
public interface IService
{
void Call(Model model);
}
public class Model
{
public int Number { get; set; }
public string Word { get; set; }
}
}
When you run this test, it fails and shows this message:
Test method MyNamespace.MyTestClass.MyTestMethod threw exception:
Moq.MockException:
Expected invocation on the mock at least once, but was never performed: mock => mock.Call(It.Is<Model>(m => m.Word == "Bar" && m.Number == 1))
No setups configured.
Performed invocations:
IService.Call(Model)
But I want it to log something along the lines of:
Performed invocations:
IService.Call(Model { Word: "Bar", Number: 1 })
Or even better:
"Assert failed for the object passed to IService.Call: The Model.Word 'Foo' is not equal to 'Bar'".
You'll probably have to verify the invocations via Mock.Invocations which is a sequence of all invocations on the mock along with the arguments that were provided. Something like the following:
var callInvocations = serviceMock.Invocations.Where(x => x.Method.Name.Equals(nameof(IService.Call)));
var matchingInvocations = callInvocations.Where(x =>
{
var model = x.Arguments.First() as Model;
return model.Word.Equals("Bar") && model.Number == 1;
});
if (!matchingInvocations.Any())
{
throw new Exception($"Performed invocations:{Environment.NewLine}{string.Join(Environment.NewLine, callInvocations.Select(x => $"{x.Method.DeclaringType.Name}.{x.Method.Name}({string.Join(", ", x.Method.GetParameters().Select((y, i) => $"{y.ParameterType.Name} {JsonConvert.SerializeObject(x.Arguments[i])}"))})"))}");
}
will give the desired output:
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.
I am using Moq library for unit testing. Now what i want is that when I access my object for the first time it should return null, and when i access this on second time it should return something else.
here is my code
var mock = new Mock<IMyClass>();
mock.Setup(?????);
mock.Setup(?????);
var actual = target.Method(mock.object);
in my method i am first checking that whether mock object is null or not, if it is null then do initialize it and then do some calls on it.
bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
else
{
myObj = new MyClass();
bool result = myObj.SomeFunctionReturningBool();
return result;
}
}
what to do setup for mock object,
Also i need to know how to mock this line
bool result = myObj.SomeFunctionReturningBool();
It sounds like you are trying to run two tests with one test method - maybe it would be better to split the tests into two?
You also want to initialise a new object if the method is passed null. To test this, I suggest creating a factory object responsible for creating instances of MyClass. The new code would look like:
interface IMyClassFactory
{
IMyClass CreateMyClass();
}
bool Method(IMyClass myObj, IMyClassFactory myClassFactory)
{
if (myObj != null)
{
return true;
}
myObj = myClassFactory.CreateMyClass();
return myObj.SomeFunctionReturningBool();
}
Then the tests would look like:
[Test]
public void Method_ShouldReturnTrueIfNotPassedNull()
{
Assert.That(target.Method(new MyClass()), Is.True);
}
[Test]
public void Method_ShouldCreateObjectAndReturnResultOfSomeFunctionIfPassedNull()
{
// Arrange
bool expectedResult = false;
var mockMyClass = new Mock<IMyClass>();
mockMyClass.Setup(x => x.SomeFunctionReturningBool()).Returns(expectedResult);
var mockMyFactory = new Mock<IMyClassFactory>();
mockMyFactory.Setup(x => x.CreateMyClass()).Returns(mockMyClass.Object);
// Act
var result = target.Method(null, mockMyFactory.Object);
// Assert
mockMyClass.Verify(x => x.SomeFunctionReturningBool(), Times.Once());
mockMyFactory.Verify(x => x.CreateMyClass(), Times.Once());
Assert.That(result, Is.EqualTo(expectedResult));
}
Here the factory pattern has been used to pass in an object which can create objects of IMyClass type, and then the factory itself has been mocked.
If you do not want to change your method's signature, then create the factory in the class's constructor, and make it accessible via a public property of the class. It can then be overwritten in the test by the mock factory. This is called dependency injection.
Moq - Return null - This working example simply illustrates how to return null using Moq. While the line of code is required is the commented line below, a full working example is provided below.
// _mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
public class Product
{
public string Id { get; set; }
public string Name { get; set; }
}
public interface IShopService
{
Product GetProduct(string productId);
}
public class ShopService : IShopService
{
public Product GetProduct(string productId)
{
if (string.IsNullOrWhiteSpace(productId))
{
return new Product();
}
return new Product { Id = "8160807887984", Name = "How to return null in Moq" };
}
}
public class Shop
{
private static IShopService _shopService;
public Shop(IShopService shopService)
{
_shopService = shopService;
}
public Product GetProduct(string productId)
{
Product product = _shopService.GetProduct(productId);
return product;
}
}
[TestClass]
public class ShopTests
{
Mock<IShopService> _mockShopService;
[TestInitialize]
public void Setup()
{
_mockShopService = new Mock<IShopService>();
}
[TestMethod]
public void ShopService_GetProduct_Returns_null()
{
//Arrange
Shop shop = new Shop(_mockShopService.Object);
//This is how we return null --- all other code above is to bring this line of code home
_mockShopService.Setup(x => x.GetProduct(It.IsAny<string>())).Returns(() => null);
//Act
var actual = shop.GetProduct(It.IsAny<string>());
//Assert
Assert.IsNull(actual);
}
}
To mock a result value you can do simply:
mock.Setup(foo => foo.SomeFunctionReturningBool()).Returns(true); // or false :)
for the other question, just pass null in the unit test instead of passing mock.object and your unit test cover that too. So you basically create two unit test one with:
var actual = target.Method(mock.object);
and the other one with:
var actual = target.Method(null);
Currently your SUT is tight-coupled with MyClass implementation. You can't mock objects which are instantiated with new keyword inside your SUT. Thus you cannot test your SUT in isolation, and your test is not unit test anymore. When implementation of MyClass.SomeFunctionReturningBool will change (it will return true instead of false), tests of your SUT will fail. This shouldn't happen. Thus, delegate creation to some dependency (factory) and inject that dependency to your SUT:
[Test]
public void ShouldReturnTrueWhenMyClassIsNotNull()
{
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
Mock<IMyClass> myClass = new Mock<IMyClass>();
var foo = new Foo(factory.Object);
Assert.True(foo.Method(myClass.Object));
}
[Test]
public void ShouldCreateNewMyClassAndReturnSomeFunctionValue()
{
bool expected = true;
Mock<IMyClass> myClass = new Mock<IMyClass>();
myClass.Setup(mc => mc.SomeFunctionReturningBool()).Returns(expected);
Mock<IMyClassFactory> factory = new Mock<IMyClassFactory>();
factory.Setup(f => f.CreateMyClass()).Returns(myClass.Object);
var foo = new Foo(factory.Object);
Assert.That(foo.Method(null), Is.EqualTo(expected));
factory.VerifyAll();
myClass.VerifyAll();
}
BTW assignment new value to method parameter does not affect reference which you passed to method.
Implementation:
public class Foo
{
private IMyClassFactory _factory;
public Foo(IMyClassFactory factory)
{
_factory = factory;
}
public bool Method(IMyClass myObj)
{
if (myObj != null)
return true;
return _factory.CreateMyClass().SomeFunctionReturningBool();
}
}
You can use TestFixture with parameter. this test will run two times and different type value.
using NUnit.Framework;
namespace Project.Tests
{
[TestFixture(1)]
[TestFixture(2)]
public class MyTest
{
private int _intType;
public MyTest(int type)
{
_intType = type;
}
[SetUp]
public void Setup()
{
if (_intType==1)
{
//Mock Return false
}
else
{
//Mock Return Value
}
}
}
}