I have a factory
$factory->define(App\Models\Polygon::class, function (Faker $faker) {
return [
'id' => 1,
'sort' => 2,
'name' => 'МКАД',
'center' => '55.73,37.75',
'points' => '[55.8977029,37.6724091],[55.8966419,37.6752415],
'parent_id' => 'N20N',
'location_id' => 'N1N',
'lat' => 55.73,
'lon' => 37.75,
'xml_id' => 'N1N'
];
});
but this factory returns the collection but i need to make model for my test.
public function testGetRouteDistance()
{
$polygon = factory(Polygon::class, 1)->create();
Are there any methods in Laravel that allow you to convert a collection into a model?
Laravel returns a model by default, with this:
public function testGetRouteDistance()
{
$polygon = factory(Polygon::class)->make();
// Use model in tests...
}
A collection is returned when you provide a second parameter like this:
public function testGetRouteDistance()
{
$polygon = factory(Polygon::class, 3)->make();
// Use model in tests...
}
Related
I am trying to test the functionality of methods related to custom fields on the user entity.
When I try to set the value of these fields in the setup method of my unit test, I get the error: Field * is unknown.
My initial test looks like this:
namespace Drupal\my_module\Entity;
use Drupal\Tests\BrowserTestBase;
class UserTest extends BrowserTestBase
{
/** #var \Drupal\my_module\Entity\User|false */
protected $user;
protected static $modules = ['field', 'user', 'commerce_payment', 'my_module'];
protected $strictConfigSchema = FALSE;
public function setUp() {
parent::setUp();
$this->user = $this->drupalCreateUser();
$this->user->addRole('member');
$this->user->set('field_user_abc', [['value' => '123']]);
}
public function testInstance1() {
$this->assertNotEmpty($this->user->get('field_user_abc')->get(0)->getValue());
}
}
It is failing at the ->set() call in the setup method.
I don't really understand why I would need to recreate the field if Drupal is bootstrapped with my project database. However, I read in some related posts that that might be the case. Following the example in /core/modules/user/tests/src/Functional/UserCreateTest.php, I tried the following, but the result was the same...
namespace Drupal\my_module\Entity;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Tests\BrowserTestBase;
class UserTest extends BrowserTestBase
{
protected $user;
protected static $modules = ['field', 'user', 'commerce_payment', 'my_module'];
protected $strictConfigSchema = FALSE;
public function setUp() {
parent::setUp();
$this->user = $this->drupalCreateUser();
$this->user->addRole('member');
$this->drupalLogin($this->user);
// Create a field.
$field_name = 'field_user_abc';
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'user',
'module' => 'core',
'type' => 'string',
'cardinality' => 1,
'locked' => FALSE,
'indexes' => [],
'settings' => [
'max_length' => 14,
'is_ascii' => false,
'case_sensitive' => false,
],
])->save();
FieldConfig::create([
'field_name' => $field_name,
'entity_type' => 'user',
'label' => 'ABC',
'bundle' => 'user',
'description' => '',
'required' => FALSE,
'settings' => [],
])->save();
$this->user->set($field_name, [['value' => '123']]);
}
public function testInstance1() {
$this->assertNotEmpty($this->user->get('field_user_abc')->get(0)->getValue());
}
}
It's because your storage type is set to string instead of text.
You should also remove the 'module' => 'core' and add text in your modules dependencies.
protected static $modules = ['field', 'text', 'user', 'commerce_payment', 'my_module'];
FieldStorageConfig::create([
'field_name' => $field_name,
'entity_type' => 'user',
'type' => 'text',
'cardinality' => 1,
'locked' => FALSE,
'indexes' => [],
'settings' => [
'max_length' => 14,
'is_ascii' => false,
'case_sensitive' => false,
],
])->save();
This will result in a varchar(14) in database.
Once you export the config, the field.storage.user.field_user_abc.yml will look like this :
uuid: 2656c022-1ff2-4868-b07d-c26ff3531aac
langcode: fr
status: true
dependencies:
module:
- text
- user
id: user.field_user_abc
field_name: field_user_abc
entity_type: user
type: text
settings:
max_length: 14
is_ascii: false
case_sensitive: false
module: text
locked: false
cardinality: 1
translatable: true
indexes: { }
persist_with_no_fields: false
custom_storage: false
I have below table structure.
Mandator table
class MandatorTable extends Table
{
public function initialize(array $config)
{
$this->table('mandators');
$this->belongsToMany('Seminar', [
'foreignKey' => 'mandator_id',
'targetForeignKey' => 'seminar_id',
'joinTable' => 'mandators_seminars'
]);
}
}
Semiar table
class SeminarTable extends Table
{
public function initialize(array $config)
{
$this->table('seminars');
$this->belongsToMany('Mandator', [
'foreignKey' => 'seminar_id',
'targetForeignKey' => 'mandator_id',
'joinTable' => 'mandators_seminars'
]);
}
}
both table are belong to 'mandators_seminars' table
mandator_id, seminar_id
When I save data it's save in seminar table but not in 'mandators_seminars' table
Query
$seminartable = $this->Seminar->newEntity();
$this->request->data['mandator'][0] = 1;
$seminardata = $this->Seminar->patchEntity($seminartable, $this->request->data);
$this->Seminar->save($seminardata)
Request data
Array
(
[bookable] => test
[released] => aaa
[linkable] => bb
[name] => ccc
[internalnote] => ddd
[abstract] => ttt
[description] => ddd
[Category] => 14
[mandator] => Array
(
[0] => 1
)
[mandator_owner_id] => 1
)
Look you have two table Mandator and Similar as singular , but your connecting table is plural. Firstly check this. If there is still a problem check this CakePHP Through Association
As you can see your association should be like this:
$this->belongsToMany('Mandator', [
'foreignKey' => 'seminar_id',
'targetForeignKey' => 'mandator_id',
'through' => 'PluginName.MandatorsSeminars'
'joinTable' => 'mandators_seminars',
'className' => 'PluginName.Mandator'
]);
And one more tip: table should be called as plural.
Code
class AclRowLevelsController extends AppController {
public $components = array(
// Don't use same name as Model
'_AclRowLevel' => array('className' => 'AclRowLevel')
);
public function view() {
$this->_AclRowLevel->checkUser();
...
}
}
class AclRowLevelComponent extends Component {
public function initialize(Controller $controller) {
$this->controller = $controller;
$this->AclRowLevel = ClassRegistry::init('AclRowLevel');
}
public function checkUser($permission, $model) {
$row = $this->AclRowLevel->find('first', array(
'conditions' => array(
'model' => $model['model'],
'model_id' => $model['model_id'],
'user_id' => $this->controller->Auth->user('id')
)
));
}
}
class AclRowLevelsControllerTest extends ControllerTestCase {
public function testViewAccessAsManager() {
$AclRowLevels = $this->generate('AclRowLevels', array(
'components' => array(
'Auth' => array(
'user'
),
'Session',
)
));
$AclRowLevels->Auth
->staticExpects($this->any())
->method('user')
->with('id')
->will($this->returnValue(1));
$this->testAction('/acl_row_levels/view/Task/1');
}
Problem
The query in the AclRowLevel component requires the Auth user id. I want to simulate user_id value '1' for the unit test.
The mocked Auth method 'user' in my test is not working for the call from the component. So the user id in that query has value null.
How should this be done?
Do a debug($AclRowLevels->Auth); to check if it really was mocked. It should be a mock object. If it is not for some reason try:
$AclRowLevels->Auth = $this->getMock(/*...*/);
The code inside checkUser() should go into the model by the way. Also I doubt this has to be a component at all. This seems to be used for authorization, so why not making it a proper authorization adapter?
This is what I was looking for:
$AclRowLevels->Auth
->staticExpects($this->any())
->method('user')
->will($this->returnCallback(
function($arg) {
if ($arg === 'id') {
return 1;
}
return null;
}
));
I make UnitTesting for my application.
I have a save saveArticleIds() Method and I wrote a testing for it -> testSaveArticelIds(). I have an dataProvider articelIdsArray() whith a multiple array. The function need that array exact like this.
/**
*
* #dataProvider articleIdsArray
*
*/
public function testSavearticleIds($articleIds) {
$articleIdObjekt = new ArticleIdHandler();
$result = $articleIdObjekt->saveArticleIds($articleIds,false);
$this->assertTrue($result);
}
public function articleIdsArray() {
return array(
array(
10552 => 10552,
14314 => 14314,
21034 => 21034,
22739 => 22739,
34568 => 34568,
34572 => 34572,
35401 => 35401,
38292 => 38292,
55141 => 55141,
161764 => 161764,
181589 => 181589
)
);
}
When I run my test, I get this Error:
There was 1 error: 1) My\Bundle\ArticleBundle\Tests\Article\ArticleIdHandlerTest::testSaveArticleIds
with data set #0 (10552, 14314, 21034, 22739, 34568, 34572, 35401, 38292, 55141, 161764, 181589)
Invalid argument supplied for foreach()
Why does it show the array like I have no keys in the array? I need the array exact like in my dataProvider! Any idea?? THANKS A LOT FOR YOU HELP!!!
maybe try this:
public function articleIdsArray()
{
return
array(
array(
array(
10552 => 10552,
14314 => 14314,
21034 => 21034,
22739 => 22739,
34568 => 34568,
34572 => 34572,
35401 => 35401,
38292 => 38292,
55141 => 55141,
161764 => 161764,
181589 => 181589
)
)
);
}
The reason is that the first level of the array nesting is the set of data provided for each round of tests, the second level represents the arguments provided to testSavearticleIds, in the same order as in the parameter list of the function (in your example there is only one argument), the last level is just the test array itself.
Hope this helps...
Try this :
/**
* #dataProvider articleIdsArray
*/
public function testSavearticleIds($articleIds)
{
$articleIdObjekt = new ArticleIdHandler();
$result = $articleIdObjekt->saveArticleIds($articleIds,false);
$this->assertTrue($result);
}
public function articleIdsArray()
{
return array(
'scenario_one' => 10552,
'scenario_two' => 14314,
...,
);
}
You doesn't need to use #dataProvider in your example.
Define your method like this
public function getArticleIdsArray() {
return array(
10552 => 10552,
14314 => 14314,
21034 => 21034,
22739 => 22739,
34568 => 34568,
34572 => 34572,
35401 => 35401,
38292 => 38292,
55141 => 55141,
161764 => 161764,
181589 => 181589
);
}
and use it in your test
public function testSavearticleIds($articleIds) {
$articleIdObjekt = new ArticleIdHandler();
$result = $articleIdObjekt->saveArticleIds($this->getArticleIdsArray(),false);
$this->assertTrue($result);
}
I am writing unit tests for my UsersController so that users can only edit their own profile. I am using CakePHP 2.4.2 and AuthComponent with Controller authorize to do this.
Auth config:
public $components = array(
'Auth' => array(
'loginRedirect' => '/',
'logoutRedirect' => '/',
'authenticate' => array('Ldap'),
'authError' => 'You are not allowed to access this page',
'authorize' => 'Controller'));
isAuthorized() in UsersController:
public function isAuthorized($user = null) {
if($this->Auth->loggedIn()) {
return $this->request->params['pass'][0] == $user['id'];
}
return false;
}
Unit test for edit:
public function testEdit() {
$result = $this->testAction('/users/view/1', array('return' => 'view'));
$this->assertRegExp('/Adam C Hobaugh/', $result);
$user = $this->generate('Users', array(
'components' => array(
'Session',
'Auth' => array('user'))));
$test = array('id' => 1);
$user->Auth->expects($this->once())->method('loggedIn')
->with($this->returnValue(true));
$user->Auth->expects($this->any())->method('user')
->with($this->returnValue($test));
$user->Session->expects($this->any())->method('setFlash');
$result = $this->testAction('/users/edit/1', array(
'return' => 'headers',
'data' => array('User' => array( {user array} ))));
debug($result);
$this->assertContains('/users', #$result['Location']);
$result = $this->testAction('/users/view/1', array('return' => 'view'));
$this->assertRegExp('/John Jacob Doe/', $result);
}
I am getting Expectation failed for method name is equal to <string:loggedIn> when invoked 1 time(s). Method was expected to be called 1 times, actually called 0 times. when I run the test. Also when I changed this->once() to $this->any() and the id in the $test array to 2, a situation that should fail and does from the browser, it succeeds in passing the test.
With those combined, it appears that isAuthorized() is not being called during the unit test. I am at a loss. Thanks for any help that you could give.
First: In your test code you call the view method and not the edit method
Second: isAuthorized() is not for this. With this method you should just define who could acces what functions, there should not be any application business logic.
Third: If you want to limit normal users to edit just their own profile you should change the dit() method to something like this.
public function edit() {
$this->request->data['User']['id'] = $this->Auth->User('id');
if ($this->request->is('post') || $this->request->is('put')) {
if ($this->User->save($this->request->data)) {
$this->Session->setFlash(__('The user has been saved.'));
return $this->redirect(array('action' => 'index'));
} else {
$this->Session->setFlash(__('The user could not be saved. Please, try again.'));
}
} else {
$this->request->data = array('User' => $this->Auth->User());
}
}
And remove echo $this->Form->input('id'); from your edit view.
I am writing a book about this topic. It will be available here soon: https://leanpub.com/CakePHPUserAuthentication/