Bizzarre behaviour on Kiwi BDD Mock - unit-testing

I'm using Kiwi to test some classes and I need to stub a class method just to return a fake file path.
I know that i can solve exposing some path property or create a subclass just for test, but i prefere to keep only one class and stub some methods.
this is the test:
it(#"return the full list of POS", ^(){
NSString *sample_data_path = [[NSBundle bundleForClass:[self class]] pathForResource:#"sample_pos" ofType:#"plist"];
Class p = [PointOfSale class];
[p stub:#selector(sampleDataPath) andReturn:sample_data_path];
NSArray *allPos = [p findAll];
[[theValue([allPos count]) should] equal:theValue(100)];
});
I'm confused because this test pass and fail alternatively, one success and one failure.
There is not any "before_each"or other running test...
someone has the same issue?

I found the cause of this issue.
The method sampleDataPath in the original and in the stub class return a file path that is supposed to be in different bundle (mainbundle and test bundle).
But even the "production" file was copied in the test bundle, so we had two file with the same name on the same bundle, because of this the result of the test was unpredictable ;)
So....if you have an issue like this,double check your file names!

Related

Mock is giving missing method exception in spock framewrok

I am running my Junit test cases for my groovy class using spock framework I am using Mock to invoke my class. but it is giving me MissingMethodException but if I invoke the same method by normal creating object def obj = new MyClass() way it is working. please let me know am I missing something? below is my stacktrace
Expected no exception to be thrown, but got 'groovy.lang.MissingMethodException'
at spock.lang.Specification.noExceptionThrown(Specification.java:119)
at .AsplTest.fetchXmlTest(AsplTest.groovy:35)
Caused by: groovy.lang.MissingMethodException: No signature of method: com.webservice.Service.fetchAsplXml() is applicable for argument types: (java.lang.String, groovy.net.xmlrpc.XMLRPCServerProxy, java.lang.String) values: [3c98fa0dd1b5d92af599779bfb7be655, groovy.net.xmlrpc.XMLRPCServerProxy#797b0699, ...]
Possible solutions: getFetchAsplXml()
at .AsplTest.fetchXmlTest(AsplTest.groovy:33)
below is my test code
public void fetchXmlTest() {
given:
def asplObject=Mock(Service);
when:
asplObject.fetchXml(sessionId, serverProxy, "https://serverproxy")
then:
noExceptionThrown()
}
FYI:
my groovy version is 2.4.12 and spock version 1.1-groovy-2.4
It seems to me that you are doing things backwards.
Mocks are not test subjects. They are used to control the interactions of your test subjects with other objects. It looks, from the code you posted, that you want to test the invocation of method fetchXml on your Service object.
To do this, you need to create an instance of Service, and call the method. If your Service has collaborating objects, then you can Mock them, and add interactions, like this:
given:
def service = new Service()
and:
service.collaboratingObject = Mock(CollaboratingObjectClass)
when:
service.getFetchAsplXml()
then:
1 * service.collaboratingObject.someMethodReturningAString(_ as String) >> {String input-> "mockedResult from $input" as String }

Mocking an Eloquent collection response from another mocked class

I Have looked at many questions along the same line of thought here on stack overflow, and else where but unable to find a solution to this particular issue.
I'm fairly new to Unit Testing in general, so the mistake may be (hopefully) obvious to someone with more experience.
Here's the issue:
I have a ResourceController that injects a class into the constructor using Depedency Injection.
public function __construct(ResourceAPIInterface $api)
{
$this->api = $api;
}
When that API is called in the controller, the class that was injected does some business logic and returns an Eloquent Collection.
public function index($resource, $version)
{
$input = Input::all();
//Populate Data
$data = $this->api->fetchAll($input);
//Format response
if($data->isEmpty()){
//Format response
$response = Response::make(" ", 204);
}else {
//Format response
$response = Response::make($data, 200);
}
//Set content-type in header
$response->header('Content-Type', 'application/json');
$response->header('Cache-Control', 'max-age=3600');
return $response;
}
As you can see from the code above, I need the response to be an eloquent response so i can test to see if it's empty. The method FetchAll literally just returns a Eloquent collation of all records in the table. When I do the test, i'm able to mock the API without issue. However when i'm mocking the response, i really want the response to be an eloquent collection, and having difficulty getting that to work. Here's an example of the test:
$course = Mockery::mock(new API\Entity\v1\Test);
$this->mock->shouldReceive('fetchAll')->once()->andReturn($course->all());
$this->mock->shouldReceive('name')->once()->andReturn('Course');
// Act...
$response = $this->action('GET', 'ResourceController#show');
// Assert...
$this->assertResponseOk();
The above works, but when i want to do the same test against the show method and mock the eloquent response for ->first() I'm getting errors.
1) ResourceControllerTest::testshow
BadMethodCallException: Method Mockery_1_API_Entity_v1_Test_API_Entity_v1_Test::first() does not exist on this mock object
I've tried to test the model by doing:
$course = Mockery::mock('Eloquent', 'API\Entity\v1\Test');
$response = $course->mock->shouldReceive('find')->with(1)->once()->andReturn((object)array('id'=>1, 'name'=>'Widget-name','description'=>'Widget description'));
However when I run that in the Test I get the following error:
1) ResourceControllerTest::testIndex
BadMethodCallException: Method Mockery_1_API_Entity_v1_Test::getAttribute() does not exist on this mock object
Any Ideas on how to resolve this issue? Also, if there's a better way to test if the eloquent collection is empty that might resolve some of the complexity that I'm running into is also welcome.
Ok, I figured out how to make this work:
public function testIndex($resource="course", $version="v1")
{
// Arrange...
$course = Mockery::mock('Eloquent', 'API\Entity\v1\Page')->makePartial();
$course->shouldReceive('isEmpty')->once()->andReturn(false);
$course->shouldReceive('all')->once()->andReturn($course);
$this->mock->shouldReceive('fetchAll')->once()->andReturn($course->all());
$this->mock->shouldReceive('name')->once()->andReturn('Course');
// Act...
$response = $this->action('GET', 'ResourceController#index');
// Assert...
$this->assertResponseOk();
}
I was able to do the PartialMock to get around the getAttribute() Error. Once I did that, I started getting the error:
Call to undefined method stdClass::isEmpty()
So I decided to mock that as well, and pass the whole mocked object into the expected response for the all command.
Then in the mock for the API class $this->mock-> i had it return The mocked eloquent collection with the ->all() method.
This is also working for the other test i had for find($id). That one however didn't require an isEmpty() check so was easier to mock.

Mocking DBSet, EF Model First

As said in the title, I follow Model First method. So my Model classes are Automatically generated. If I want mock the DBContext derived MyModelContainer which contain DBSets of entity classes. Read some where that in order to unit test, you need to change it to IDBSet. Whether its possible to do it especially in a class that gets auto generated when I do "Run Custom Tool" is one concern. But as of now I modified it.
But the real problem is: when I try to Stub MyModelContainer to return a mock generated from IDBSet. Rhino mock is firing an InvalidOperationException: "Invalid call, the last call has been used, or no call has been made(make sure that you are calling a virtual(C#)/Overridable(VB) method."
Here is my unit test code.
MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
dbMock.Stub( x=>x.MyEntities ).Return( entityMock );
The last statement is triggering the exception. I tried using the fake implementation of IDBSet<> specified here, But no luck!
I use MVC 4, Rhino Mocks 3.6. Any help will be appreciated.
Update:
After some trials and research, I found a fix. I changed the code to:
MyModelContainer dbMock = MockRepository.GenerateMock<MyModelContainer>();
IDBSet<Models.MyEntity> entityMock = MockRepository.GenerateMock<IDBSet<Models.MyEntity>>()
//dbMock.Stub( x=>x.MyEntities ).Return( entityMock );
dbMock.MyEntities = entityMock;
Now the InvalidOperationException is gone.
The test fails only due to ExpectationViolationException which should be normal.
As for auto generated Model class, it is found out that editing the DbContext's T4 template (.tt extension) will do the trick. Thanks to Alan's Blog
But I want to know why the previous code didn't work. Anyone?
2 reasons are possible here:
MyEntites property of MyModelContainer is not virtual.
In that case Rhino Mock can't stub this property at all. Then dbMock.Stub(x=>x.MyEntities) will fail.
MyEntites property is virtual, but has both public getter and public setter.
Then notation dbMock.Stub(x=>x.MyEntities).Return(entityMock) is not allowed. You can see explanation e.g. here.
In both cases the right fix is exactly what you did: use dbMock.MyEntities = entityMock instead of dbMock.Stub(x=>x.MyEntities).Return(entityMock).
Here is an extension method for Substituting IDbSet (with NSubstitute) to return an IQueryable
public static DbSet<T> FakeDbSet<T>(this IQueryable<T> queryable) where T : class
{
DbSet<T> fakeDbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
((IQueryable<T>)fakeDbSet).Provider.Returns(queryable.Provider);
((IQueryable<T>)fakeDbSet).Expression.Returns(queryable.Expression);
((IQueryable<T>)fakeDbSet).ElementType.Returns(queryable.ElementType);
((IQueryable<T>)fakeDbSet).GetEnumerator().Returns(queryable.GetEnumerator());
fakeDbSet.AsNoTracking().Returns(fakeDbSet);
return fakeDbSet;
}
Then you can now stub the DbContext like this:
var db = NSubstitute.Substitute.For<DataContext>();
var fakeResult = emptyCustomers.FakeDbSet();
db.Customers.Returns(fakeResult);
Here is an extension method for Stubing (with RhinoMocks) IDbSet to return an IQueryable
public static class RhinoExtensions
{
public static IDbSet<T> MockToDbSet<T>(this IQueryable<T> queryable) where T : class
{
IDbSet<T> mockDbSet = MockRepository.GenerateMock<IDbSet<T>>();
mockDbSet.Stub(m => m.Provider).Return(queryable.Provider);
mockDbSet.Stub(m => m.Expression).Return(queryable.Expression);
mockDbSet.Stub(m => m.ElementType).Return(queryable.ElementType);
mockDbSet.Stub(m => m.GetEnumerator()).Return(queryable.GetEnumerator());
return mockDbSet;
}
}
Then you can now stub the DbContext like this:
_db.Stub(p => p.Customers).Return(fakeCustomers.MockToDbSet());

Mock a method for Grails Unit Test

In one of my unit tests, I am having some difficulty getting a mocked method to executed. I have the following test code:
void testExample() {
def mockICFService = new MockFor(ICFService)
...
//Mock the methods
controller.metaClass.icfList = { def person ->
println "icfList"
return [new IC(conceptId:'12345')]
}
mockICFService.demand.getAllIC(1..1) { def id, def withHist, def appId ->
println "mocking service"
return new Person()
}
...
def model = controller.detail()
}
Inside of detail in my controller class I create a Person via the ICFService's getAllIC(). This part works correctly. Later in the function, however, there is a call to icfList (which is defined in the controller). Through println's I have determined that the call is still being made, although it is returning an empty array. I believe that this is because the array is populated based on data in the servletContext, but in Unit Testing there is no access to that (hence my trying to mock it out).
Does anyone know how to force the test to use the mocked version of controller.icfList instead of calling the actual method in controller?
When I try your code, what blows up for me is the mocked service, and the part that works properly is the mocked-out icfList() method. The opposite of your observation, interestingly. For what it's worth, here's what I did:
First replace new MockFor() class instantiation with the mockFor() method. Then you need to inject the mock service into the controller.
def mockICFService = mockFor(ICFService)
controller.iCFService = mockICFService.createMock()
By doing the above, only the mocked versions of icfList() and getAllIC() get called, so you are not using the servletContext at all. Check out the Grails testing documentation for more info.

How can I correctly move grails unit-test helper methods into a seperate file?

I have some often-used helper methods for unit tests put into a seperate file. The idea is to, for example, allow my XYZTests.groovy to call TestHelper.getUserObject() in order to get a fully initialized instance of User.
Now the problem is, that there's a springSecurityService.encodePassword(pw) being called in the User's beforeInsert() which always fails as there's no mock for springSecurityService in TestHelper.groovy.
java.lang.NullPointerException: Cannot invoke method encodePassword() on null object
In User.groovy:
def beforeInsert() {
// ...
password = springSecurityService.encodePassword(pw)
// ...
}
Note: I would like to avoid any mocking in TestHelper.groovy in order to use it's methods in integration tests too.
In spite of that, even if I try to call a mockFor() anywhere in the TestHelper.groovy, I get an MME:
No signature of method: static myproject.TestHelper.mockFor() is applicable for argument types: (java.lang.Class, java.lang.Boolean) values: [class grails.plugins.springsecurity.SpringSecurityService, true]
groovy.lang.MissingMethodException: No signature of method: static myproject.TestHelper.mockFor() is applicable for argument types: (java.lang.Class, java.lang.Boolean) values: [class grails.plugins.springsecurity.SpringSecurityService, true]
at myproject.TestHelper.mockSpringSecurityService(TestHelper.groovy:59)
at myproject.TestHelper$mockSpringSecurityService.callStatic(Unknown Source)
at myproject.TestHelper.getUserObject(TestHelper.groovy:47)
at myproject.TestHelper$getUserObject.call(Unknown Source)
at myproject.UserTests.setUp(UserTests.groovy:26)
Note: I currently mock the springSecurityService.encodePassword like this:
// in UserTests.groovy
protected void setUp() {
// mockDomain(...) and such here
def u = TestHelper.getUserObject("Pummel")
u.springSecurityService = mockSpringSecurityService()
assert u.save()
}
private mockSpringSecurityService() {
def ssService = mockFor(SpringSecurityService,true)
ssService.metaClass.encodePassword() { password ->
"08a2d3c63bf9fc88276d97a9e8df5f841fd772724ad10f119f7e516f228b74c6"
}
ssService
}
Any ideas on how I may be able to use the helper class while leaving all mocking in the unit tests only?
Where would I best place the TestHelper.groovy file for using it in integration AND unit tests?
Note that everything is working perfectly fine when I move all helpers into UserTests.groovy directly!
The solution to this is to refrain from calling any user.save() in the TestHelper.groovy.
This makes sense, as for many (unit) tests a persisted (saved) instance is unnecessary anyways.
On the other hand many cases actually require an unsaved intance. (In order to test certain effects of the .save() itself, for example)
A working example for integration tests would be:
def user = TestHelper.getUserObject()
user.save()
For a unit tests:
def user = TestHelper.getUserObject()
user.springSecurityService = new SpringSecurityService() // or the described mock accordingly
user.save()
This keeps any mocks out of TestHelper.groovy
In your TestHelper you can use Groovy ExpandoMetaClass metaClass.static to slap a mock closure for encodePassword on SpringSecurityService:
SpringSecurityService.metaClass.'static'.encodePassword = {'08a2d3c63bf9fc88276d97a9e8df5f841fd772724ad10f119f7e516f228b74c6'}
I would stick this class in a test package under src/groovy