Im using FakeItEasy to mock methods for unit tests. One of method (using REF parameter - maybe this is important) saves data in database, so it's mocked as 'Does Nothing'
A.CallTo(() => mockedUserRepository.Save(ref mwbeUserData)).DoesNothing();
. But in this situation last assert fails
A.CallTo(() => mockedUserRepository.Save(ref mwbeUserData)).MustHaveHappened(Repeated.Exactly.Once);
with error:
Assertion failed for the following call:
MobileWallet.Common.DAL.IMwbeUserRepository.Save(<NULL>)
Expected to find it exactly once but found it #0 times among the calls:
1: MobileWallet.Common.DAL.IMwbeUserRepository.Get(userName: \"AAA\")
2: MobileWallet.Common.DAL.IMwbeUserRepository.Save(user: MobileWallet.Common.Repository.MwbeUserData)
Full code of test
[TestMethod]
public void AddUser_MwbeUserObjectReturned()
{
//Arrange
MwbeUserRegistrationIn userRegistrationIn = new MwbeUserRegistrationIn()
{
BirthDate = DateTime.Today,
Email = "www#wp.pl",
FirstName = "Adam",
SecondName = "Ada2",
UserName = "AAA"
};
//mock mockedNotificationService and related:
INotificationService mockedNotificationService = A.Fake<INotificationService>();
//TODO: create notofication service
//mock IMwbeUserRepository and related
IMwbeUserRepository mockedUserRepository = A.Fake<IMwbeUserRepository>();
MwbeReturnData<MwbeUserData> mwbeReturnData = new MwbeReturnData<MwbeUserData>(MwbeResponseCodes.NotFound);
MwbeUserData mwbeUserData = mwbeReturnData.Data;
A.CallTo(() => mockedUserRepository.Get(userRegistrationIn.UserName)).Returns(mwbeReturnData);
A.CallTo(() => mockedUserRepository.Save(ref mwbeUserData)).DoesNothing();
MwbeUserService userService = new MwbeUserService(mockedUserRepository, mockedNotificationService);
//Act
MwbeUser user = userService.AddUser(userRegistrationIn);
//Assert
Assert.IsNotNull(user);
Assert.AreEqual(userRegistrationIn.Email, user.Email);
Assert.AreEqual(userRegistrationIn.UserName, user.UserName);
Assert.AreEqual(userRegistrationIn.FirstName,user.FirstName);
Assert.AreEqual(userRegistrationIn.SecondName, user.SecondName);
Assert.AreEqual(userRegistrationIn.BirthDate, user.BirthDate);
A.CallTo(() => mockedUserRepository.Get(userRegistrationIn.UserName)).MustHaveHappened(Repeated.Exactly.Once);
A.CallTo(() => mockedUserRepository.Save(ref mwbeUserData)).MustHaveHappened(Repeated.Exactly.Once);
}
UPDATE 1:
Please notice that for both calls to this method Save, value of mwbeUserData is the same
MwbeUserData mwbeUserData = mwbeReturnData.Data;
If this is null (but it's not).
Maybe the is problem with syntax for REF parameter? I read that there should be used method called AssignsOutAndRefParameters, but I dont know exactly how to use it.
For now I will use MATCHES parameter to make it more generic.
I believes that it's occurred because you assert against mwbeUserData instance
#Old Fox has the right of it.
You're asking FakeItEasy if mockedUserRepository.Save(ref mwbeUserData) was called with null input (mwbeUserData must be null at the time you make the check). It saw nothing like that, since the MwbeUserData that was passed to mockedUserRepository.Save inside AddUser appears to have been not null.
If you think the test should've passed, perhaps relaxing your constraint will help, as in FakeItEasy: mocked method is not returning expected result.
Also, note that the refness of the parameter has no effect on this behaviour. the same constraint matching would occur for a "plain" parameter. Only out parameters are exempted by default. See Argument Constraints in the FakeItEasy documentation for more information about this, and more on how to use custom argument matchers.
Related
I'm trying to implement an adapter that is using a Yii model object extending yii\db\ActiveRecord. The object is passed as constructor arg to the adapter class.
My issue is now that I still couldn't figure out how to get this to work properly. I've even tried mocking it but got stuck because Yii is using lots of static methods to get it's objects. Sure, I could now try to mock them... But there must be a better way?
public function testSuccessFullFind(): void
{
$connection = (new Connection([
'dsn' => 'sqlite:test'
]))
->open();
$queryBuilder = new \yii\db\sqlite\QueryBuilder($connection);
$app = $this->createMock(Application::class);
\Yii::$app = $app;
$app->expects($this->any())
->method('getDb')
->willReturn($this->returnValue($connection));
$userModel = new UserModel();
$resovler = new Yii2Resolver($userModel);
$result = $resolver->find(['username' => 'test', 'password' => 'test']);
// TBD asserts for the result
}
The UserModel is used to find a user record internally.
This results in:
1) Authentication\Test\Identifier\Resolver\Yii2ResolverTest::testSuccessFullFind
Error: Call to a member function getDb() on null
vendor\yiisoft\yii2-dev\framework\db\ActiveRecord.php:135
vendor\yiisoft\yii2-dev\framework\db\ActiveQuery.php:312
vendor\yiisoft\yii2-dev\framework\db\Query.php:237
vendor\yiisoft\yii2-dev\framework\db\ActiveQuery.php:133
tests\TestCase\Identifier\Resolver\Yii2ResolverTest.php:31
The code above is obviously the WIP of a test case.
So how can I configure a test connection and get my ActiveRecord object to use it?
You can pass connection as argument of all() method:
$results = UserModel::find()->where(['id' => 1])->all($connection);
I have a method on an interface:
string GetUserDetails(string whatever);
I want to mock this with MOQ, so that it returns whatever the method returns i.e user details - something like:
_mock.Setup( theObject => theObject.GetUserDetails( It.IsAny<string>( ) ) )
.Returns( [object return by GetUserDetails method] ) ;
Any ideas?
For situation described in question, you need to use partial mocking. In Moq there are two different ways to achieve it:
Specifying CallBase on construction: var mock = new Mock<MyClass> { CallBase = true }; . In this case by default call on this object methods will execute real method implementation if any.
Specifying CallBase for some specific method: mock.Setup(m => m.MyMethod()).CallBase();
See also When mocking a class with Moq, how can I CallBase for just specific methods?
I'm fairly new to using Moq and Nunit for unit testing and I'm having issues with one scenario. What I want is for my mock to have an out parameters which my system under test will then use to decide what action to take.
My system under test is an MVC API controller and in particular I'm trying to test the POST method. I want to return an error message for the object when validation fails.
Here is the method code for the controller:
public IHttpActionResult Post(Candidate candidate)
{
try
{
if(candidate==null)
return BadRequest();
IEnumerable<string> errors;
_candidateManager.InsertCandidate(candidate, out errors);
if (errors!=null && errors.Any())
return BadRequest(CreateErrorMessage("Invalid candidate: ", errors));
return CreatedAtRoute("DefaultApi", new {id = candidate.CandidateId}, candidate);
}
catch (Exception)
{
return InternalServerError();
}
}
This is my Unit Test Code:
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
var mockManager = new Mock<ICandidateManager>();
mockManager.Setup(x => x.InsertCandidate(new Candidate(), out errors)).Callback(()=>GetErrors(errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(new Candidate());
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
What I expect is that when _candidateManager.InsertCandidate() is run then the errors variable is populated. However what is happening is that when you step through the controller code errors is null after _candidateManager.InsertCandidate() method is run.
If anyone has any ideas what I'm doing wrong or if what I want to do is not possible using Moq then please let me know.
Thanks
What you want to do is possible. If you look at the Quickstart docs at https://github.com/Moq/moq4/wiki/Quickstart, there is a section where it shows how you do setups for methods using out params. I have made two corrections to your code and it works.
You have to use the same candidate instance for both the mock setup and when you exercise the sut. Otherwise, Moq thinks that the two objects are different and your test setup becomes useless.
You don't have to use Callback in order to set the errors returned by the mocked CandidateManager.
Below is your test method with my changes.
[Test]
[Category("CandidateManagerController Unit Tests")]
public void Should_Return_Bad_Request_When_Creating_Invalid_Candidate()
{
IEnumerable<string> errors = new List<string>() {"error1", "error2"};
//instance to be used for both setup and test later
var candidate = new Candidate();
var mockManager = new Mock<ICandidateManager>();
//removed Callback
mockManager.Setup(x => x.InsertCandidate(candidate, out errors));
var sut = new CandidateManagerController(mockManager.Object);
var actionResult = sut.Post(candidate);
Assert.IsInstanceOf<BadRequestResult>(actionResult);
}
You have to make sure that when you call your SUT that you use the same instance passed to the out argument otherwise the call will fail.
In your example, the method under test passes a null instance into the mocked method thus negating the setup of the test.
If however you are not able to supply the same instances for the out then it doesn't look like you will be able to get a mock to pass successfully. Take a look a the Quick Start for Moq to get an understanding of it capabilities.
I've got a service, which is using sendJMSMessage method which is provided by jms-grails plugin.
I want to write some unit tests, but I'm not sure how to "mock" this method, so it just does nothing at all.
Any tips?
You can metaClass the method to have it return whatever you want.
#Test
void pluginCode() {
def myService = new MyService()
def wasCalled = false
myService.metaClass.sendJMSMessage = {String message ->
//I like to have an assert in here to test what's being passed in so I can ensure wiring is correct
wasCalled = true
null //this is what the method will now return
}
def results = myService.myServiceMethodThatCallsPlugin()
assert wasCalled
}
I like to have a wasCalled flag when I'm returning null from a metaClassed method because I don't particularly like asserting that the response is null because it doesn't really assure that you're wired up correctly. If you're returning something kind of unique though you can do without the wasCalled flag.
In the above example I used 1 String parameter but you can metaClass out any number/type of parameters to match what actually happens.
Is it possible to mock a stub/mock's object member call without having to define that as a stub, and also set the return value as all seperate verbose lines?
Example:
[TestMethod]
public void AssignedPermissions_AssociateExists_ReturnsEdit_Rhino()
{
//Arrange
var fakeConfiguration = MockRepository.GenerateStub<IDomainControllerConfiguration>();
var fakeAssociateRepository = MockRepository.GenerateStub<IAssociateRepository>();
fakeConfiguration.Stub(x => x.AssociateRepository).Return(fakeAssociateRepository);
fakeAssociateRepository.Stub(x=>x.GetAssociatesByRole(null,false,null)).IgnoreArguments()
.Return(new IAssociate[]{MockRepository.GenerateStub<IAssociate>()});
var domain = new DomainController(fakeConfiguration);
const AssignedPermission expected = AssignedPermission.Edit;
//Act
AssignedPermission actual = domain.AssignedPermissions();
//Assert
Assert.AreEqual(expected, actual);
}
Are all those temporary variables necessary just to stub out nested method calls?
I've never used the functionality, so I'm not 100% certain that this will work, but theoretically Rhino mocks supports "recursive mocking", which should allow you to at least cut out the fakeAssociateRepository by doing something like this:
var fakeConfiguration = MockRepository.GenerateStub<IDomainControllerConfiguration>();
fakeConfiguration.Stub(x => x.AssociateRepository.GetAssociatesByRole(null,false,null))
.IgnoreArguments()
.Return(new IAssociate[]{MockRepository.GenerateStub<IAssociate>()});
var domain = new DomainController(fakeConfiguration);
(note: code not tested, or even compiled)
Just wanted to share my input on this, since I just spent the last few hours wrestling with it. The answer posted above by Alconja absolutely works, but if you plan to use it for "AssertWasCalled" type of assertion, it does not assert the way I expected it to. It seems that the AssertWasCalled methods tried to assert the "get accessor" associated with the "nested" object.
For instance, if you wanted to do this:
fakeconfiguration.AssertWasCalled(x => x.AssociateRepository.GetAssociatesByRole(null, false, null));
You would get an exception such as
System.InvalidOperationException : Previous method 'IDomainControllerConfiguration.get_AssociateRepository();' requires a return value or an exception to throw.
Because the AssertWasCalled is asserting the get-accessor of the AssociateRepository property, rather than the GetAssociatesByRole() method. In the end, for my case I had to use the OP's methodology of creating mutliple stubs.