I am tring to write test cases for my controller in cakephp, so far i have managed to mock the controller and include the auth component which is used in my controller function. the problem is it seems that i can call staticExpects only once, which means that i can define a return value for only one function call, i don't want that, i need to call staticExpects more than once within the same test case.
Here is a part of my code.
$this->TasksController = $this->generate('Tasks', array(
'components' => array('Session','Auth' => array('User'), ) ));
$this->TasksController->Auth->staticExpects($this->any())
->method('User')
->with('userID')
->will($this->returnValue(224));
$this->TasksController->Auth->staticExpects($this->any())
->method('User')
->with('accID')
->will($this->returnValue('some ID here'));
whenever i do this and run the test it gives me this error
Expectation failed for method name is equal to when invoked zero or more times
Parameter 0 for invocation AuthComponent::user('userID') does not match expected value.
Failed asserting that two strings are equal.
Please help :)
You have to specify when the static methods are called using $this->at(index).
$this->TasksController->Auth->staticExpects($this->at(1))
->method('user')
->with('userID')
->will($this->returnValue(224));
$this->TasksController->Auth->staticExpects($this->at(2))
->method('user')
->with('accID')
->will($this->returnValue('some ID here'));
If you're not sure when they are called try each expectation one by one until the error messages will give you what is called
--- Expected
+++ Actual
## ##
-'userID'
+'accID'
One last thing, the correct method name is "user" and not "User"
Related
In the context of a Flutter 2.0.5 app whose state I'd like to manage with Riverpod, I thought I can declare a StateNotifierProvider like this:
import 'package:flutter_riverpod/flutter_riverpod.dart';
final counterProvider = StateNotifierProvider<CounterStateNotifier>((ref) => CounterStateNotifier());
class CounterStateNotifier extends StateNotifier<int> {
CounterStateNotifier([int count = 0]) : super(count);
void increment() => state++;
}
But Android Studio (and later the Dart compiler as well) complains about the line where I declare the counterProvider variable:
The type 'StateNotifierProvider' is declared with 2 type parameters, but 1 type arguments were given.
Removing the <CounterStateNotifier> type parameter in StateNotifierProvider<CounterStateNotifier> removes the error. However, attempting to read the provider and call its increment method (setting () => context.read(counterProvider).increment() as the onPressed of an ElevatedButton, then pressing the button) gives the following runtime error:
'increment'
method not found
Receiver: 0
Arguments: []
Why is context.read(counterProvider) returning the int state instead of the notifier? And what is the reason behind the type parameter error mentioned in the first part of my question?
I should mention that I'm running my app on the web (with flutter run -d Chrome).
As of Riverpod 0.14.0, State is the default value exposed by StateNotifierProvider.
The syntax for declaring your StateNotifierProvider is now as follows:
final counterProvider = StateNotifierProvider<CounterStateNotifier, int>((ref) => CounterStateNotifier());
Accessing functions now requires adding .notifier (accessing the StateNotifier itself):
context.read(counterProvider.notifier).increment();
And like you've noticed, you now access the state like so:
final count = context.read(counterProvider);
More on the changes here.
You may also use dynamic to accept any type if value for the StateNotifierProvider
final modelProvider =
StateNotifierProvider.autoDispose<ModelClassName, dynamic>(
(ref) => ModelClassName());
I'm novice about phpunit.
I use this snippet to mock my EntityManager
$emMock = $this->getMock('\Doctrine\ORM\EntityManager',
array('getRepository', 'getClassMetadata', 'persist', 'flush'), array(), '', false);
$emMock->expects($this->any())
->method('getRepository')
->will($this->returnValue(new \it\foo\Entity\File()));
$emMock->expects($this->any())
->method('persist')
->will($this->returnValue(null));
$emMock->expects($this->any())
->method('getClassMetadata')
->will($this->returnValue((object) array('name' => 'aClass')));
$emMock->expects($this->any())
->method('flush')
->will($this->returnValue(null));
When I run my test I have this error
Error: Call to undefined method it\foo\Entity\File::findBy()
How can I mock this method?
If you look at your code, you will see, that at least one line of it calls getRepository() and uses the result to apply function findBy() on it. This is a very standard behavior of a Doctrine2 program.
You are mocking only the EntityManager - you have the mock in the variable $emMock. One of the (mocked) functions, getRepository() returns an object of class \it\foo\Entity\File, which you create in line 5.
I suppose that class \it\foo\Entity\File doesn't implement the same interface as a Doctrine2 repository, at least it obviously doesn't implement findBy(), so the error message occurs.
To solve this problem, you need to replace the return value of the mock function for getRepository with either e real Repository (which is normally not what you want in a unit test) or another mock:
$repoMock = $this->getMock('Doctrine\ORM\EntityRepository', [], [], '', false);
$emMock->expects($this->any())
->method('getRepository')
->will($this->returnValue($repoMock);
Most likely you have to mock some of the functions in the Repository as well, for example findBy() which may return the list of entries you want your test to work with.
I have created rspec tests for my scopes (scope1, scope2 and scope3) and they pass as expected but I would also like to add some tests for a class method that I have which is what is actually called from my controller (the controller calls the scopes indirectly via this class method):
def self.my_class_method(arg1, arg2)
scoped = self.all
if arg1.present?
scoped = scoped.scope1(arg1)
end
if arg2.present?
scoped = scoped.scope2(arg2)
elsif arg1.present?
scoped = scoped.scope3(arg1)
end
scoped
end
It seems a bit redundant to run the same scope tests for each scenario in this class method when I know they already pass so I assume I really only need to ensure that different scopes are called/applied dependant on the args being passed into this class method.
Can someone advise on what this rspec test would look like.
I thought it might be something along the lines of
expect_any_instance_of(MyModel.my_class_method(arg1, nil)).to receive(:scope1).with(arg1, nil)
but that doesn't work.
I would also appreciate confirmation that this is all that's necessary to test in this situation when I've already tested the scopes anyway would be reassurring.
The Rspec code you wrote is really testing the internal implementation of your method. You should test that the method returns what you want it to return given the arguments, not that it does it in a certain way. That way, your tests will be less brittle. For example if you change what scope1 is called, you won't have to rewrite your my_class_method tests.
I would do that by creating a number of instances of the class and then call the method with various arguments and check that the results are what you expect.
I don't know what scope1 and scope2 do, so I made an example where the arguments are a name attribute for you model and the scope methods simply retrieve all models except those with that name. Obviously, whatever your real arguments and scope methods do you should put that in your tests, and you should modify the expected results accordingly.
I used the to_ary method for the expected results since the self.all call actually returns an ActiveRecord association and therefore wouldn't otherwise match the expected array. You could probably use includes and does_not_includes instead of eq, but perhaps you care about the order or something.
describe MyModel do
describe ".my_class_method" do
# Could be helpful to use FactoryGirl here
# Also note the bang (!) version of let
let!(:my_model_1) { MyModel.create(name: "alex") }
let!(:my_model_2) { MyModel.create(name: "bob") }
let!(:my_model_3) { MyModel.create(name: "chris") }
context "with nil arguments" do
let(:arg1) { nil }
let(:arg2) { nil }
it "returns all" do
expected = [my_model_1, my_model_2, my_model_3]
expect_my_class_method_to_return expected
end
end
context "with a first argument equal to a model's name" do
let(:arg1) { my_model_1.name }
let(:arg2) { nil }
it "returns all except models with name matching the argument" do
expected = [my_model_2, my_model_3]
expect_my_class_method_to_return expected
end
context "with a second argument equal to another model's name" do
let(:arg1) { my_model_1.name }
let(:arg2) { my_model_2.name }
it "returns all except models with name matching either argument" do
expected = [my_model_3]
expect_my_class_method_to_return expected
end
end
end
end
private
def expect_my_class_method_to_return(expected)
actual = described_class.my_class_method(arg1, arg2).to_ary
expect(actual).to eq expected
end
end
I am trying to test a method with PhpUnit and Mockery. In the process of specifying a method should be called with arguments my test fails.
TEST:
$this->eventRepo = \Mockery::mock('Path\To\EventRepository');
$start = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-21-00');
$end = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-19-00');
$this->eventRepo
->shouldReceive('findEvent')
->withArgs([
$start,
$end,
'1',
'1234567891'
])
->andReturn($callEvent);
REAL CODE:
$start = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-20-00');
$end = Carbon::createFromFormat('Ymd-H-i-s', '20141211-09-20-00');
$event = $this->eventRepo->findEvent(
$start->subSeconds(60),
$end->addSeconds(60),
$id,
$number
);
ERROR FROM TEST:
Mockery\Exception\NoMatchingExpectationException: No matching handler found for EventRepo::findEvent(object(Carbon\Carbon), object(Carbon\Carbon), "1", "1234567891"). Either the method was unexpected or its arguments matched no expected argument list for this method
$this->eventRepo is a mocked in the test. The real code runs correctly. After the error displays, it, I guess var_dump()'s a instance of Carbon.
I have no idea what could be causing this. I tried googling it but not knowing what to google made that pretty worthless. Has anyone run into this before?
When using an object in with() or withArgs(), phpunit performs an === check. This means that it'll look for the exact same instance of the class, not just any instance of Carbon.
In this case, it means that findEvent() is receiving an instance of Carbon, but not the exact same instance that you have in the actual code.
So, in my method A in the controller ServicioComunitario I send this to the GSP:
tg = ServicioComunitario.findAll("from ServicioComunitario as b where "+query)
[servicioComunitarioInstanceList: tg, params: params]
Then in the GSP I call another method (generarDocDeReporte) of ServicioComunitarioController:
<g:set var="b" value="${'xls'}"/>
<g:set var="a" value="${'excel'}"/>
<g:set var="servicioLista" value="${servicioComunitarioInstanceList}"/>
<g:link controller="ServicioComunitario" action="generarDocDeReporte"
params="${[exportFormat:a, extesion:b, tg: servicioLista] }"
update="mainContent">Excel</g:link><br/>
Then, in the new method "generarDocDeReporte" I have:
println params.exportFormat+"-"+params.extesion
if(params.tg)
println "Not empty"
exportFormat and extension work as expected, but the params.tg doesn't seem to behave normal.
I am trying to use this new params.tg where it was a ServicioComunitario.list(params):
exportService.export(params.exportFormat, response.outputStream, ServicioComunitario.list(params), fields, labels, formatters, parameters)
And here is where I get the error:
exportService.export(params.exportFormat, response.outputStream, params.tg, fields, labels, formatters, parameters)
When I receive the params.tg, do I need to cast it? or what do you think is the error?
Thank you very much in advance
You can't just pass a list of instances like that in a link. You can however collect the ids into a list as a parameter and then use it to populate it later. For example:
<g:link controller="ServicioComunitario" action="generarDocDeReporte"
params="${[exportFormat:a, extesion:b, tgids: servicioLista.collect{it.id}.join(',')] }"
update="mainContent">Excel</g:link><br/>
And then in your controller where you need to get the list again:
def tg = ServicioComunitario.getAll(params?.tgids?.tokenize(","))
Also, you don't need to assign params to params when returning your model. parameters are already exposed in the GSP by convention.
[servicioComunitarioInstanceList: tg]