I have a call to a factory interface that creates an IMachine in a command handler. This returned IMachine from the factory has methods that can be chained together to create itself inside of a builder class. The problem I am running into with FakeItEasy right now is that it only recognized the first call (which is WithSpeeds) unless I configure every method call to return a fake IMachine. Is there a way not to configure every single call or have FakeItEasy recognize every method call on the chain? I know I must be doing something incorrect because if i use OrderAssertions, and fail the order on purpose without setting up my fake machine, it shows calls were made to all the methods. Thanks for the help.
Part of the Command Handler's Method
public void Handle(FooCommand commandParm)
{
var entity = new Entity.Builder
{
Machine = _factory.CreateMachine(commandParm.MachineName)
.WithSpeeds(commandParm.ProcessingSpeed, commandParm.StartupSpeed, commandParm.ShutDownSpeed)
.WithOils(commandParm.Lubrication, commandParm.FinishingOil)
};
}
Test
[TestMethod]
public void HandleSetMachineSettings_should_build_machine()
{
// Arrange
var settings = CommandUtilities.ReturnFooCommand();
var _factory = A.Fake<IMachineFactory>();
var machine = A.Fake<IMachine>();
A.CallTo(() => _factory.CreateMachine(settings.MachineName)).Returns(machine);
// Act
_handler.Handle(settings);
// Assert
machine.Should().NotBeNull();
A.CallTo(machine).Where(x => x.Method.Name.Equals("set_MachineNumber")).WhenArgumentsMatch(arg => arg.Get<int>(0) == settings.MachineNumber).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => machine.WithSpeeds(commandParm.ProcessingSpeed, commandParm.StartupSpeed, commandParm.ShutDownSpeed)).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => machine.WithOils(commandParm.Lubrication, commandParm.FinishingOil)).MustHaveHappened(Repeated.Exactly.Once);
}
I take it that WithSpeeds and WithOils both return an IMachine, yes?
The problem is:
_factory.CreateMachine returns one IMachine, machine from your setup
machine.WithSpeeds returns a fake IMachine that FakeItEasy makes up. This is not machine, but is a different fake, call it "machine2"
machine2.WithOils returns yet another fake machine
Your Assert block suggests that you expected the same machine to be returned at each step of the builder chain. Try inserting
A.CallTo(machine)
.WithReturnType<IMachine>()
.Returns(machine);
after A.CallTo(() => _factory.CreateMachine()).Returns(machine);
That way machine will keep returning itself, and the appropriate properties will be set on it and whatnot.
Related
I have a section of code that calls a factory, and then uses the returned object.
var myServiceObject = factoryService.GetTheObject(myParam);
myServiceObject.DoSomeWork(someData, moreData); // returns void
I'm writing a test with Automock where I want to verify that I call the factory and that I attempt to use the object.
For mocking the factory I'm assuming I need it to return an instance?
mock.Mock<IFactoryService>().Setup(x => x.GetTheObject(It.IsAny<paramType>()))
.Returns({insertSomething});
I was going to use a mock object, and do something like this:
mock.Mock<IMyService>().Setup(x => x.DoSomeWork(...));
var mockOfMyService = mock.Provide<IMyService>(new MockOfMyService()); // MockOfMyService inherits from IMyService
mock.Mock<IFactoryService>().Setup(x => x.GetTheObject(It.IsAny<paramType>()))
.Returns(mockOfMyService);
...
mock.Mock<IFactoryService>().Verify(...); // This passes
mock.Mock<IMyService>().Verify(x => x.DoSomeWork(...), Times.Once); // This errors
But I'm getting an invalid cast exception on the verify. Any good examples out there? What am I doing wrong?
So, for this one, I received some help outside of SO. Here's what worked for me:
mock.Mock<IMyService>().Setup(x => x.DoSomeWork(...));
var mockOfMyService = mock.Mock<IMyService>().Object; // Slight change here
mock.Mock<IFactoryService>().Setup(x => x.GetTheObject(It.IsAny<paramType>()))
.Returns(mockOfMyService);
...
mock.Mock<IFactoryService>().Verify(...); // This passes
mock.Mock<IMyService>().Verify(x => x.DoSomeWork(...), Times.Once); // And now this passes
I am writing unit tests for the existing Web API 2 project. For which i am using Ploeh Autofixture and Moq.
Test Method :
UPDATED
[Test]
public async Task Service1_TestMethod() {
//some code here
var fakeemail = FakeBuilder.Create<string>("test1234#test.com");
var fakeUserInvite =
FakeBuilder.Build<UserInvite>()
.With(i => i.EmailAddress, fakeemail)
.With(i => i.Username, fakeemail)
.Create();
var fakeUserToken = FakeBuilder.Create<string>();
var fakeHttpResponseMessage =
Fixture.Build<HttpResponseMessage>()
.With(h => h.StatusCode, HttpStatusCode.OK).Create();
//Here i am mocking another service method. Whose response is HttpResponseMessage.
Service2.Setup(i => i.AddUser(fakeUserInvite, fakeUserToken))
.ReturnsAsync(fakeHttpResponseMessage);
var result = await Service1.AddUser( /* */);
}
Service1 Method :
public async Task<bool> AddUser(/* */)
{
var response = await Service2.AddUser(userInvite, userToken); // response is null even after mocking it.
// Add user code follows bassed on the above response.
}
If i comment the Service2.AddUser call then everything works. There is a lot of code in that method apart from this call. I am having problem with only this call. If this call returns the mocked HttpResponseMessage then everything works.
Service2 is an external API. I am just wondering how to mock HttpResponseMessage. Any help is appreciated.
The stub you create with:
service2.Setup(i => i.AddUser(fakeUserInvite, fakeUserToken))
.ReturnsAsync(fakeHttpResponseMessage);
requires the actual call to be made with the exact same objects as the ones referenced by fakeUserInvite and fakeUserToken in order for Moq to return fakeHttpResponseMessage.
This is because Moq's argument matching verifies that the arguments specified in the stub are equal to the ones made in the actual call. If they are not, the stub won't match and Moq will return the default value for the method's return type – in this case null since HttpResponseMessage is a reference type.
To solve this problem, you can either make sure that the fakeUserInvite and fakeUserToken references are being passed to the actual service2.AddUser call or you can use somewhat less specific argument constraints.
Here's an example:
service2.Setup(i => i.AddUser(
It.Is<UserInvite>(u => u.EmailAddress == fakeEmail &&
u.Username == fakeEmail),
fakeUserToken))
.ReturnsAsync(fakeHttpResponseMessage);
Here we're stating that the AddUser method should be called with:
A UserInvite object whose EmailAddress and Username properties have the same value as fakeEmail as the first argument
The same value as fakeUserToken as the second argument
If the actual values of those arguments don't matter to your specific test scenario, you can tell Moq to always return fakeHttpResponseMessage regardless of what arguments AddUser is being called with by saying:
service2.Setup(i => i.AddUser(
It.IsAny<UserInvite>(),
It.IsAny<string>()))
.ReturnsAsync(fakeHttpResponseMessage);
I'm using Moq for my Unit Tests and have got the following method:
[TestMethod]
public void GetTestRunById_ValidId_TestRunReturned()
{
var mockTestRunRepo = new Mock<IRepository<TestRun>>();
var testDb = new Mock<IUnitOfWork>();
testDb.SetupGet(m => m.TestRunsRepo).Returns(mockTestRunRepo.Object);
TestRun returnedRun = EntityHelper.getTestRunByID(testDb.Object, 1);
}
The method in question which is being tested is getTestRunByID(). I have confirmed that this method is called when debugging this unit test, but as expected getTestRunByID() doesn't return anything since the mock has no data inside it.
Would all that matter is the method gets hit and returns null? If not, how can I add data to my mockTestRunRepo when it's only present as a returned value from testDb?
For reference the method being tested is:
public static TestRun getTestRunByID(IUnitOfWork database, int testRun)
{
TestRun _testRun = database.TestRunsRepo.getByID(testRun);
return _testRun;
}
The purpose of the unit test is to ONLY test the small method getTestRunByID. For that, test if it was called exactly once with that integer parameters, 1.
mockTestRunRepo.Verify(m => m.getByID(1), Times.Once());
You must also set up the method getByID for mockTestRunRepo, to make it return a specific value, and test if the result value of the test run is equal to what you expected.
//instantiate something to be a TestRun object.
//Not sure if abstract base class or you can just use new TestRun()
mockTestRunRepo.Setup(m => m.getByID(1)).Returns(something);
Test if you get the same value
TestRun returnedRun = EntityHelper.getTestRunByID(testDb.Object, 1);
Assert.AreEqual(returnedRun, something);
This code might be prone to errors, as I do not have an environment to test it right now. But this is the general idea behind a unit test.
This way, you test if the method getById runs as expected, and returns the expected result.
You have your repository return data the same way that you setup everything else.
var mockTestRunRepo = new Mock<IRepository<TestRun>>();
// This step can be moved into the individual tests if you initialize
// mockTestRunRepo as a Class-level variable before each test to save code.
mockTestRunRepo.Setup(m => m.getById(1)).Returns(new TestRun());
Per #Sign's recommendation, if you know that you're calling it with 1, then use that instead of It.IsAny<int>() to keep things cleaner.
I want to assert that a call on my real object (system under test) was called. Here is my test
// Arrange
var contextFactory = A.Fake<IContextFactory>();
var db = A.Fake<IDatabase>();
A.CallTo(() => contextFactory.GetContext()).Returns(db);
var vm = new MainViewModel(contextFactory);
// Act
vm.Loaded();
// Assert
A.CallTo(() => vm.LoadModels(db)).MustHaveHappened();
I'm getting an ArgumentException that says "The specified object is not recognized as a fake object." How do I test that the LoadModels() method in my MainViewModel gets called from the Loaded() method?
EDIT
The reason I'm doing it this way is because the Loaded() method calls a bunch of other methods when the app starts and I don't want to have to setup all the other stuff for each test, I just want to make sure that all the proper methods get called and then test them individually. I'm open to suggestion for a better way of going about this.
Here are the Loaded and LoadModels methods
internal virtual void Loaded()
{
using (var db = _contextFactory.GetContext())
{
LoadModels(db);
// bunch of other method calls
}
}
internal virtual void LoadModels(IDatabase db)
{
Models = new ObservableCollection<Model>(db.Models);
}
It looks like you're verifying a method (vm.LoadModels) that isn't part of the fake (db). You can only verify methods on a fake, not methods that happen to take the fake as an argument.
I ended up moving the functionality of LoadModels() to another class that implements IStartupDataLoader and then I was able to test it like this
// Arrange
var sdl = A.Fake<IStartupDataLoader>();
var exp = A.Fake<ObservableCollection<Model>>();
A.CallTo(() => sdl.LoadModels()).Returns(exp);
var sut = new MainViewModel(sdl);
// Act
sut.Loaded();
// Assert
Assert.That(exp == sut.Models);
Using Microsoft Test Framework and Moq I'm trying to verify if a log4net method was called.
[TestMethod()]
public void Log_Info_When_Stuff_Is_Done()
{
SampleClass sampleObject = new SampleClass();
Mock<log4net.ILog> logMockObject = new Mock<log4net.ILog>();
sampleObject.Log = logMockObject.Object;
sampleObject.DoStuffAndLogInfo();
logMockObject.Verify(moqLog => moqLog.Info("do stuff got called"), Times.AtLeastOnce());
}
I get an exception on Verify call saying that
Expected invocation on the mock at least once, but was never
performed: moqLog => moqLog.Info("do stuff got called") No setups
configured. No invocations performed.
What am I doing wrong?
update the problem was with a getter for SampleClas.Log property. I was always returning LogManager.GetLogger(...); even when the property was already set to a ILogProxy. I was under impression that the property's get accessor won't be called because I've set up a proxy like so sampleObject.Log = logMockObject.Object;
Right now Moq is verifying that DoStuffAndLogInfo calls Info with the exact string "do stuff got called". If it's actually calling Info with a different argument, and you don't care what the actual argument is, use the following instead:
logMockObject.Verify(moqLog => moqLog.Info(It.IsAny<string>()), Times.AtLeastOnce());
The test is correctly set up.
Check your sut to see if Log.Info actually gets called inside the DoStuffAndLogInfo method.
This doesn't look to be the original poster's problem, but in my case I had a very similar error message. It was due to my .Verify() call before the actual execution. For example, this is wrong:
SampleClass sampleObject = new SampleClass();
Mock<log4net.ILog> logMockObject = new Mock<log4net.ILog>();
logMockObject.Verify(moqLog => moqLog.Info(It.IsAny<string>()), Times.AtLeastOnce());
sampleObject.Log = logMockObject.Object;
sampleObject.DoStuffAndLogInfo();
....but this is right:
SampleClass sampleObject = new SampleClass();
Mock<log4net.ILog> logMockObject = new Mock<log4net.ILog>();
sampleObject.Log = logMockObject.Object;
sampleObject.DoStuffAndLogInfo();
logMockObject.Verify(moqLog => moqLog.Info(It.IsAny<string>()), Times.AtLeastOnce());