I have a mostly working unit test that checks a method is called, which works fine. However I would like to check the parameters that are passed to that method. Using Verify I can check if a particular set of arguments are passed, but if these are not passed and the test fails, is there a way of seeing what was actually passed to the method?
Example:
sut.Setup(x => x.MyMethod(It.IsAny<myClass>()).Verifiable();
sut.Object.DoAThing();
sut.Verify(x => x.MyMethod(It.Is<myClass>(v => v.thing == 1)));
In my test this will fail (v.thing will be something other than 1), but what I would like to know is, what IS v.thing set to? I'd like to know as I find this kind of feedback really helpful in debugging my code and unit tests.
The error I am getting is simply saying that x.MyMethod (with those expected parameters) was never called.
Is there a solution? am I missing something obvious?
Minimal Example to illustrate my point:
public class myClass
{
public struct myStruct {
public int thing;
}
public virtual void MyMethod(myStruct x )
{
// Code goes here
}
}
public class sutClass
{
public myClass target = new myClass();
public void DoAThing()
{
myClass.myStruct toBePassed = new myClass.myStruct { thing = 8 };
target.MyMethod(toBePassed);
}
}
[TestMethod]
public void Test1()
{
Mock<myClass> mMyClass = new Mock<myClass>();
sutClass sut = new sutClass();
sut.target = mMyClass.Object;
mMyClass.Setup(x => x.MyMethod(It.IsAny<myClass.myStruct>())).Verifiable();
sut.DoAThing();
mMyClass.Verify(x => x.MyMethod(It.Is<myClass.myStruct>(v => v.thing == 1)));
}
The above simple test will obviously return a fail.
Expected invocation on the mock at least once, but was never performed: x => x.MyMethod(It.Is<myStruct>(v => v.thing == 1))
What I would like to see is an output of what WAS passed to MyMethod what was the difference between what was expected and what actually happened. Much like Assert.AreEqual(expected, actual) would return. (the expected string and the actual string for example).
You can implement a callback in your mock setup:
[TestMethod]
public void Test1()
{
Mock<myClass> mMyClass = new Mock<myClass>();
sutClass sut = new sutClass();
sut.target = mMyClass.Object;
int passedValue = 0;
mMyClass.Setup(x => x.MyMethod(It.IsAny<myClass.myStruct>())).Callback<myClass.myStruct>((s) => { passedValue = s.thing; Console.Write(s.thing); });
sut.DoAThing();
mMyClass.Verify(x => x.MyMethod(It.Is<myClass.myStruct>(v => v.thing == 1)));
}
Here the value is set to passedValue and printed to the console
Related
I have some problem when I setup my mock for add entity. In case when I want get entity/entites my mock-setup is working fine, but when I want create(add). I setup method for create and it returned null in result.
P.S AddProductAsync in my suspicion, this method may not work, although I checked in the debug, there is a call to the method
public class ProductServiceTests
{
private Mock<IProductRepository> _productMockRepo = new Mock<IProductRepository>();
private ProductService _sut;
public ProductServiceTests()
{
_sut = new ProductService(_productMockRepo.Object);
}
It's my test method
[Fact]
public async Task AddProduct_ShouldReturnProduct_WhenInputDataIsCorrect()
{
//Arrange
var productId = Guid.NewGuid().ToString();
var actualProduct = new ProductModel
{
Name = "test",
Price = 1,
Category = Category.Foods,
Quantity = 2
};
var addingProduct = new Product
{
Name = actualProduct.Name,
Price = actualProduct.Price,
Category = actualProduct.Category,
Quantity = actualProduct.Quantity
};
_productMockRepo.Setup(x => x.AddProductAsync(addingProduct))
.ReturnsAsync(addingProduct);
//Act
var result = await _sut.AddProductAsync(actualProduct);
//Assert
Assert.Equal(actualProduct.Name, result.Name);
_productMockRepo.Verify(x => x.AddProductAsync(addingProduct), Times.Once);
}
}
_sut is my service and _productMockRepo is my mock repository
For testing I use NuGet packadge "Moq"
Thanks)
The issue is that the expectation was setup to use addingProduct, a specific instance
_productMockRepo.Setup(x => x.AddProductAsync(addingProduct))
.ReturnsAsync(addingProduct);
but when exercising the test it is getting another instance created within the member under test
var result = await _sut.AddProductAsync(actualProduct);
which I can only assume does something similar to what was done in the here
var addingProduct = new Product {
Name = actualProduct.Name,
Price = actualProduct.Price,
Category = actualProduct.Category,
Quantity = actualProduct.Quantity
};
since the subject under test (ie: ProductService.AddProductAsync(Product product)) is not shown.
Because it is not the actual instance used in the setup the mock will return null by default.
In this case, loosen the argument match during setup of expected behavior
//...
_productMockRepo
.Setup(x => x.AddProductAsync(It.IsAny<Product>())) //<-- loosen expected match
.ReturnsAsync((Product p) => p); //<-- return the argument that was passed to the member
//...
and change the expression for the verification to inspect what was passed
_productMockRepo.Verify(x => x.AddProductAsync(It.Is<Product>(p => addingProduct.Name == p.Name && ... )), Times.Once);
Reference: MOQ Quickstart - Matching Arguments
I am currently working with Moq to do some unit testing. I am running into an issue where I am specifying what my mocked object returns, but the actual call is returning null instead of what I am specifying in .Returns(...). I've reviewed other posts and one of the suggestions was to create the mock with MockBehavior.Strict- after doing this, I get a fairly verbose error as follows:
IMyRepository.Save(MvcIndividualAuth.Data.Models.DTO.MyTableDTO) invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.
However, I am calling setup on the only method that my mocked object calls already. Please see code below:
My test:
MyService _myService;
Mock<IMyRepository> _myRepoMock;
[TestInitialize]
public void Setup()
{
_myRepoMock = new Mock<IMyRepository>();
_myService = new MyService(_myRepoMock.Object);
}
[TestMethod]
public void MyServiceSave()
{
//Arrange
var myDto = new MyTableDTO { Id = 1, Bar = 5, Foo = "Test" };
_myRepoMock.Setup(x => x.Save(myDto)).Returns(myDto);
//Act
var vm = _myService.Save(new MyTableViewModel(myDto));
//Assert
Assert.AreEqual(vm.Id, 1);
Assert.AreEqual(vm.Foo, "Test");
Assert.AreEqual(vm.Bar, 5);
Assert.AreEqual(vm.BarPlusFoo, "5 Test");
}
MyService.Save method:
public MyTableViewModel Save(MyTableViewModel viewModel)
{
var dto = MyTableViewModel.GetDto(viewModel);
var dbDto = _myRepo.Save(dto); //_myRepo is of type IMyRepository,
// this _myRepo.Save call is returning null
var vm = new MyTableViewModel(dbDto);
return vm;
}
Why is the mocked repo in my test not returning the value I specify in my .Returns(..) call? All help is appreciated.
EDIT: as requested, here is MyRepository.Save method and MyTableViewModel.GetDto():
MyRepository.Save:
public MyTableDTO Save(MyTableDTO dto)
{
try
{
var entity = new MyTable();
if (String.IsNullOrEmpty(dto.Foo))
{
throw new ArgumentException("MyTable requires Foo");
}
if (dto.Id == 0)
{
//added
entity.Update(dto);
_db.MyTables.Add(entity);
}
else
{
//modified
entity = _db.MyTables.Single(x => x.Id == dto.Id);
entity.Update(dto);
}
_db.SaveChanges();
return new MyTableDTO(entity);
}
catch (Exception)
{
throw;
}
}
MyTableViewModel.GetDto(..);
public static MyTableDTO GetDto(MyTableViewModel vm)
{
var dto = new MyTableDTO
{
Bar = vm.Bar,
Foo = vm.Foo,
Id = vm.Id
};
return dto;
}
You get null because GetDto() returns object different from myDto - references are different.
You can change your Setup() to return myDto:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns(myDto);
Or if you want to return object which was passed as a parameter:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => dto);
Or if you want to mock based on some properties:
_myRepoMock.Setup(x => x.Save(It.Is<MyTableDTO>(dto => dto.Id == 1))).Returns(myDto);
Or if you want to modify return result:
_myRepoMock.Setup(x => x.Save(It.IsAny<MyTableDTO>())).Returns((MyTableDTO dto) => { dto.Id = 2; return dto;});
You can also combine all approaches.
The MyTableDTO returned by GetDTO is a new MyTableDTO which is not the same as the rule in your Setup, because it has a different reference, hence there is no matching setup for Save.
Instead you can try something like:
_myRepo.Setup(s => s.Save(It.Is<MyTableDTO>(d => d.Equals(myDto))).Returns(myDto);
Or, if you are not concerned about the exact values passed to Save:
_myRepo.Setup(s => s.Save(It.IsAny<MyTableDTO>()).Returns(myDto);
Currently we are trying to implement some unittesting on our services. In the below service an order is created and a audit registration is made about the creation of an order. When writing the two tests (because we think the tests should be seperated to get tests with 1 responsibility) this was where I started with:
public class TestPacklineOrderManagementService
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine {Id = 1});
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1 && x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x=>null);
var rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(new RawProduct { Id = 1 });
var packlineRepository = Substitute.For<IPackLineRepository>();
packlineRepository.Get(1).Returns(new PackLine { Id = 1 });
var auditRegistrationService = Substitute.For<IAuditRegistrationService>();
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository, rawProductRepository, packlineRepository, auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
As you can see a lot of duplicate code. To prevent this I tried to refactor this and it resulted in the code below:
public class TestPacklineOrderManagementService2
{
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1,1);
packLineOrderRepository.Received().Insert(Arg.Any<PackLineOrder>());
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
IPackLineOrderRepository packLineOrderRepository;
IAuditRegistrationService auditRegistrationService;
var packlineOrderManagementService = BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out packLineOrderRepository, out auditRegistrationService);
packlineOrderManagementService.SetProduct(1, 1);
auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item => item.Action == PackLineOrderAction.CreatePacklineOrder));
}
private PacklineOrderManagementService BuilderForCreateNewProductWhenNoPacklineOrderIsAvailable(out IPackLineOrderRepository packLineOrderRepository,
out IAuditRegistrationService auditRegistrationService)
{
packLineOrderRepository = CreatePackLineOrderRepository(x => null);
auditRegistrationService = CreateAuditRegistrationService();
var rawProductRepository = CreateRawProductRepository(x => new RawProduct { Id = 1 });
var packlineRepository = CreatePacklineRepository(x => new PackLine { Id = 1 });
var packlineOrderManagementService = new PacklineOrderManagementService(packLineOrderRepository,
rawProductRepository, packlineRepository, auditRegistrationService);
return packlineOrderManagementService;
}
private IPackLineOrderRepository CreatePackLineOrderRepository(Func<CallInfo, PackLineOrder> getActiveResult)
{
IPackLineOrderRepository packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(getActiveResult);
return packLineOrderRepository;
}
private IRawProductRepository CreateRawProductRepository(Func<CallInfo, RawProduct> getResult)
{
IRawProductRepository rawProductRepository = Substitute.For<IRawProductRepository>();
rawProductRepository.Get(1).Returns(getResult);
return rawProductRepository;
}
private IPackLineRepository CreatePacklineRepository(Func<CallInfo, PackLine> getResult)
{
IPackLineRepository packLineRepository = Substitute.For<IPackLineRepository>();
packLineRepository.Get(1).Returns(getResult);
return packLineRepository;
}
private IAuditRegistrationService CreateAuditRegistrationService()
{
return Substitute.For<IAuditRegistrationService>();
}
}
Is there any way to get a better code base for our unittests?
Better is very subjective, it depends a lot on how you define it. Some people might argue that your first example was better since all of the setup code is together in your test. I do have some feedback based on your code above though...
When you're writing tests, don't use the same value for two parameters to your system under test (SUT) unless they really are the same, it hides transposition errors. So, in your test, you're setting up one of your substitutes like this:
rawProductRepository.Get(1).Returns(new RawProduct {Id = 1});
Then calling your SUT:
packlineOrderManagementService.SetProduct(1,1);
Are the 1s in the SUT call related to the Repository setup? It's not at all clear which 1 is which...
This somewhat subjective, but if your test setup is exactly the same, do you really need to duplicate the test, with different asserts? Does it really make sense for the Audit to take place if the Insert hasn't etc?
If you do have groups of tests that have similar setups, then you could push the common bits into your classes constructor. You could also organise your tests using nested classes, something like this:
public class TestPacklineOrderManagementService
{
public class TestSetProduct {
IPackLineOrderRepository _packLineOrderRepository;
IRawProductRepository _rawProductRepository;
// etc
public TestSetProduct() {
_packLineOrderRepository = Substitute.For<IPackLineOrderRepository>();
_packLineOrderRepository.GetActive(Arg.Any<PackLine>()).Returns(x => null);
_rawProductRepository = Substitute.For<IRawProductRepository>();
// etc
}
[Fact]
public void CreateNewProductWhenNoPacklineOrderIsAvailable()
{
// Any test specific setup...
_packlineOrderManagementService.SetProduct(1,1);
_packLineOrderRepository.Received()
.Insert(Arg.Is<PackLineOrder>(x => x.PackLine.Id == 1
&& x.Product.Id == 1));
}
[Fact]
public void AuditCreateNewProductWhenNoPacklineOrderIsAvailable()
{
_packlineOrderManagementService.SetProduct(1, 1);
_auditRegistrationService.Received()
.Audit(Arg.Is<PackLineOrderAudit>(item =>
item.Action == PackLineOrderAction.CreatePacklineOrder));
}
}
public class TestSomeOtherScenario {
// tests...
}
}
This approach and make your tests more succinct and easier to follow, if they only contain the test specific information, but is it better? It's very subjective, some people (including the xunit team) don't like shared per test setups. Really it's about finding the approach that works for you and your team...
I've hit a snag when using Moq to simulate an dependency which is called a large number of times. When I call Verify, Moq takes a long time (several minutes) to respond, and sometimes crashes with a NullReferenceException (I guess this is understandable, given the amount of data that Moq would have to accumulate to do the Verify from a "cold start").
So my question is, is there another strategy that I can use to do this using Moq, or should I revert to a hand-crafted stub for this rather unusual case. Specifically, is there a way to tell Moq up front that I'm only interested in verifying specific filters on the parameters, and to ignore all other values?
Neither of the approaches below is satisfactory.
Given CUT and Dep:
public interface ISomeInterface
{
void SomeMethod(int someValue);
}
public class ClassUnderTest
{
private readonly ISomeInterface _dep;
public ClassUnderTest(ISomeInterface dep)
{
_dep = dep;
}
public void DoWork()
{
for (var i = 0; i < 1000000; i++) // Large number of calls to dep
{
_dep.SomeMethod(i);
}
}
}
Moq Strategy 1 - Verify
var mockSF = new Mock<ISomeInterface>();
var cut = new ClassUnderTest(mockSF.Object);
cut.DoWork();
mockSF.Verify(mockInt => mockInt.SomeMethod(It.Is<int>(i => i == 12345)),
Times.Once());
mockSF.Verify(mockInt => mockInt.SomeMethod(It.Is<int>(i => i == -1)),
Times.Never());
Moq Strategy 2 - Callback
var mockSF = new Mock<ISomeInterface>();
var cut = new ClassUnderTest(mockSF.Object);
bool isGoodValueAlreadyUsed = false;
mockSF.Setup(mockInt => mockInt.SomeMethod(It.Is<int>(i => i == 12345)))
.Callback(() =>
{
if (isGoodValueAlreadyUsed)
{
throw new InvalidOperationException();
}
isGoodValueAlreadyUsed = true;
});
mockSF.Setup(mockInt => mockInt.SomeMethod(It.Is<int>(i => i == -1)))
.Callback(() =>
{ throw new InvalidOperationException(); });
cut.DoWork();
Assert.IsTrue(isGoodValueAlreadyUsed);
Usually when such a limitation is reached, I would reconsider my design (no offense, I see your rep). Looks like the method under test does too much work, which is violation of the single responsibility principle. It first generates a large list of items, and then verifies a worker is called for each one of them, while also verifying that the sequence contains the right elements.
I'd split the functionality into a sequence generator, and verify that the sequence has the right elements, and another method which acts on the sequence, and verify that it executes the worker for each element:
namespace StackOverflowExample.Moq
{
public interface ISequenceGenerator
{
IEnumerable<int> GetSequence();
}
public class SequenceGenrator : ISequenceGenerator
{
public IEnumerable<int> GetSequence()
{
var list = new List<int>();
for (var i = 0; i < 1000000; i++) // Large number of calls to dep
{
list.Add(i);
}
return list;
}
}
public interface ISomeInterface
{
void SomeMethod(int someValue);
}
public class ClassUnderTest
{
private readonly ISequenceGenerator _generator;
private readonly ISomeInterface _dep;
public ClassUnderTest(ISomeInterface dep, ISequenceGenerator generator)
{
_dep = dep;
_generator = generator;
}
public void DoWork()
{
foreach (var i in _generator.GetSequence())
{
_dep.SomeMethod(i);
}
}
}
[TestFixture]
public class LargeSequence
{
[Test]
public void SequenceGenerator_should_()
{
//arrange
var generator = new SequenceGenrator();
//act
var list = generator.GetSequence();
//assert
list.Should().Not.Contain(-1);
Executing.This(() => list.Single(i => i == 12345)).Should().NotThrow();
//any other assertions
}
[Test]
public void DoWork_should_perform_action_on_each_element_from_generator()
{
//arrange
var items = new List<int> {1, 2, 3}; //can use autofixture to generate random lists
var generator = Mock.Of<ISequenceGenerator>(g => g.GetSequence() == items);
var mockSF = new Mock<ISomeInterface>();
var classUnderTest = new ClassUnderTest(mockSF.Object, generator);
//act
classUnderTest.DoWork();
//assert
foreach (var item in items)
{
mockSF.Verify(c=>c.SomeMethod(item), Times.Once());
}
}
}
}
EDIT:
Different approaches can be mixed to define a specific expectations, incl. When(), the obsoleted AtMost(), MockBehavior.Strict, Callback, etc.
Again, Moq is not designed to work on large sets, so there is performance penalty. You are still better off using another measures to verify what data will be passed to the mock.
For the example in the OP, here is a simplified setup:
var mockSF = new Mock<ISomeInterface>(MockBehavior.Strict);
var cnt = 0;
mockSF.Setup(m => m.SomeMethod(It.Is<int>(i => i != -1)));
mockSF.Setup(m => m.SomeMethod(It.Is<int>(i => i == 12345))).Callback(() =>cnt++).AtMostOnce();
This will throw for -1, for more than one invocation with 12, and assertion can be made on cnt != 0.
I want to test a construct which calls a method within it twice to get two different values
public class stubhandler
{
public stubhandler()
{
string codetext = model.getValueByCode(int a,string b); // 1,"High" result Canada
string datatext = model.getValueByCode(int a,string b); // 10, "Slow" result Motion
}
}
To test the above i use a unit test class
[TestMethod]
public void StubHandlerConstructor_Test()
{
Mock<Model> objMock = new Mock<>(Model);
objMock.Setup(m => m.getValueByCode(It.IsAny<int>,It.IsAny<string>)).Returns("Canada");
objMock.Setup(m => m.getValueByCode(It.IsAny<int>,It.IsAny<string>)).Returns("Motion");
stubhandler classstubhandler = new stubhandler();
}
The above method pass but codetext and datatext contains same value Motion
i want them to set to
codetext = Canada
datatext = Motion
How can i achieve this?
I have tried objMock.VerifyAll() which fails the test ??
If using MOQ 4 one can use SetupSequence, else it can be done using a lambda
Using SetupSequence is pretty self explanatory.
Using the lambdas is not too messy. The important point to not it that the return value is set at the time that the setup is declared. If one just used
mockFoo.Setup(mk => mk.Bar()).Returns(pieces[pieceIdx++]);
the setup would always return pieces[0]. By using the lambda, the evaluation is deferred until Bar() is invoked.
public interface IFoo {
string Bar();
}
public class Snafu {
private IFoo _foo;
public Snafu(IFoo foo) {
_foo = foo;
}
public string GetGreeting() {
return string.Format("{0} {1}",
_foo.Bar(),
_foo.Bar());
}
}
[TestMethod]
public void UsingSequences() {
var mockFoo = new Mock<IFoo>();
mockFoo.SetupSequence(mk => mk.Bar()).Returns("Hello").Returns("World");
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetGreeting());
}
[TestMethod]
public void NotUsingSequences() {
var pieces = new[] {
"Hello",
"World"
};
var pieceIdx = 0;
var mockFoo = new Mock<IFoo>();
mockFoo.Setup(mk => mk.Bar()).Returns(()=>pieces[pieceIdx++]);
var snafu = new Snafu(mockFoo.Object);
Assert.AreEqual("Hello World", snafu.GetGreeting());
}
Moq documentation says you can simulate something like successive returns with Callback method:
var values = new [] { "Canada", "Motion" };
int callNumber = 0;
mock.Setup(m => m.getValueByCode(It.IsAny<int>(), It.IsAny<string>()))
.Returns((i,s) => values[callNumber])
.Callback(() => callNumber++);
This will do the trick, but it's not the most elegant solution. Matt Hamilton proposes much better one in his blog post, with clever use of queue:
var values = new Queue<string> { "Canada", "Motion" };
mock.Setup(m => m.getValueByCode(It.IsAny<int>(), It.IsAny<string>()))
.Returns(() => values.Dequeue());
Calling mock.Object.getValueByCode twice, will produce "Canada" and "Motion" strings respectively.