Knowing to interpret the phpunit tests - yii

I´m trying to configure the fixtures and phpunit system is returned the next message '.E', but I don´t know how interpret it:
C:\kyopol\Apache 2.22.22\htdocs\demo\protected\tests>phpunit unit/EntityTest.php
PHPUnit 3.7.14 by Sebastian Bergmann.
Configuration read from C:\kyopol\Apache
2.22.22\htdocs\demo\protected\tests\phpunit.xml
.E
Time: 2 seconds, Memory: 6.50Mb
There was 1 error:
1) EntityTest::testRead Undefined variable: newEntity
C:\kyopol\Apache
2.22.22\htdocs\demo\protected\tests\unit\EntityTest.php:37
FAILURES! Tests: 2, Assertions: 3, Errors: 1.
Next, class test EntityTest.php data code:
class EntityTest extends CDbTestCase
{
public function testCreate()
{
//CREATE a new Entity
$newEntity=new Entity;
$newEntity->setAttributes(
array(
'name' => 'Test Entity 1',
'description' => 'Test entity number one',
'type_id' => 1,
'location_lat' => 77,
'location_lon' => 77,
'create_time' => '2013-02-16 20:36:00',
'create_user_id' => 1,
'update_time' => '0000-00-00 00:00:00',
'update_user_id' => 0,
)
);
$this->assertTrue($newEntity->save(false));
//READ a Entity
$retrievedEntity=Entity::model()->findByPk($newEntity->id);
$this->assertTrue($retrievedEntity instanceof Entity);
$this->assertEquals('Test Entity 1',$retrievedEntity->name);
}
public function testRead()
{
//READ a Entity
$retrievedEntity=Entity::model()->findByPk($newEntity->id);
$this->assertTrue($retrievedEntity instanceof Entity);
$this->assertEquals('Test Entity 1',$retrievedEntity->name);
}
}
What is it meaning the capital letter 'E' and the previous point '.' ?
In general: Could nobody said me how knows to interpret output messages in phpunit?
Cheers.

One of your tests is failing so that's why you see the E. The other one is passing, indicated by a ..
If there are any error messages in the tests they will be summarized at the end.
The error message of your failing test is "Undefined variable: newEntity".
Your first line in testRead() is:
$retrievedEntity=Entity::model()->findByPk($newEntity->id);
But you have never setup $newEntity in that test.

Related

PDO's fetch method passes wrong parameter to constructor class (in Yii)

Model class MyModel has following behavior
public function behaviors() {
return [
'CTimestampBehavior' => [
'class' => 'zii.behaviors.CTimestampBehavior',
'createAttribute' => null,
'updateAttribute' => 'update_time',
'setUpdateOnCreate' => true
]
];
}
In code, in controller I write something like
$model = new MyModel();
$dataReader = Yii::app()->db->createCommand()
->selectDistinct('some fields')
->from('MyModel')
->leftJoin('some table')
->where('some criteria')
->query();
while ($item = $dataReader->readObject('MyMode', $model->getAttributes())) {
**//!!! HERE item array is with model attributes, which are empty**
$items[] = $item;
}
disaster, it's not working, items is array, each of element holding empty list of attributes, like no data fetched from db
If I write
$dataReader = Yii::app()->db->createCommand()
->selectDistinct('some fields')
->from('MyModel')
->leftJoin('some table')
->where('some criteria')
->query();
while ($item = $dataReader->readObject('MyModel', MyModel::model()->getAttributes())) {
//!!! HERE item array is with model attributes, which hold correct data, taken from db
$items[] = $item;
}
it's working
If I get rid off CTimestamp behavior, both cases work.
If I debug first case, I realize that, after pdo fetchobject is done, it calls constructor with scenario="current_timestamp()". Question is why? And where I missstepped?
If you read readObject() documentation you will find that second argument is not list of fields, but list of constructor arguments. CActiveRecord has only one constructor argument - $scenario. $dataReader->readObject('MyMode', $model->getAttributes()) essentially assigns random value as scenario, since it will get first value from $model->getAttributes(). In your case you probably need:
$item = $dataReader->readObject('MyModel', []);

Testing updating user profile data

I make http tests in my Laravel 5.7 application with profile page(which has "Profile View" page and "Profile Details" editor ), like :
$newUser->save();
$testing_user_id = $newUser->id;
$newUserGroup = new UserGroup();
$newUserGroup->group_id = USER_ACCESS_USER;
$newUserGroup->user_id = $newUser->id;
$userGroup= Group::find($newUserGroup->group_id);
$newUserSessionData = [
[
'loggedUserAccessGroups' => ['group_id' => $newUserGroup->group_id, 'group_name' => !empty($userGroup) ? $userGroup->name : ''],
'logged_user_ip' => '0',
]
];
$newUserGroup->save();
// 3. OPEN PROFILE PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('/profile/view');
// 3. OPEN PROFILE PAGE BLOCK END
// 4. MAKING CHECKING PROFILE FOR USER CREATED AT 2) BLOCK START
$response->assertStatus(200); // to use HTTP_RESPONSE_OK
$response->assertSee(htmlspecialchars("Profile : " . $newUser->username, ENT_QUOTES));
// 4. MAKING CHECKING PROFILE FOR USER CREATED AT 2) BLOCK END
// 5. OPEN PROFILE DETAILS VIEW PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/view');
$response->assertStatus(200);
$response->assertSee(htmlspecialchars("Profile : " . $newUser->username, ENT_QUOTES));
// 5. OPEN PROFILE DETAILS VIEW PAGE BLOCK END
// 6. OPEN PROFILE DETAILS EDITOR PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/edit-details'); // http://local-votes.com/profile/edit-details
$response->assertStatus(HTTP_RESPONSE_OK);
$response->assertSee(htmlspecialchars("Profile : Details"));
// 6. OPEN PROFILE DETAILS EDITOR PAGE BLOCK END
// 7. MODIFY PROFILE DETAILS PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->post('profile/edit-details-post', [
'first_name' => 'Modified : ' . $newUser->first_name,
'last_name' => 'Modified : ' . $newUser->last_name,
'phone' => 'Modified : ' . $newUser->phone,
'website' => 'Modified : ' . $newUser->website,
'_token' => $csrf_token
]);
// $response->assertStatus(205); // ???
// 7. MODIFY PROFILE DETAILS PAGE BLOCK END
////////////////////////
// 8. OPEN PROFILE DETAILS VIEW PAGE AFTER MODIFICATIONS BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/view');
$response->assertStatus(200);
$response->assertSee( htmlspecialchars('Modified : ' . $newUser->last_name) );
// 8. OPEN PROFILE DETAILS VIEW PAGE AFTER MODIFICATIONS BLOCK END
New user is added and Profile View page is opened ok, but there are problems at step // 7. MODIFY PROFILE DETAILS PAGE BLOCK START
as I see in sql trace new user is inserted but not updated.
In my control app/Http/Controllers/ProfileController.php update method is defined with validation request :
public function update_details(ProfileUserDetailsRequest $request)
{
$userProfile = Auth::user();
$requestData = $request->all();
$userProfile->first_name = $requestData['first_name'];
$userProfile->last_name = $requestData['last_name'];
$userProfile->phone = $requestData['phone'];
$userProfile->website = $requestData['website'];
$userProfile->updated_at = now();
$userProfile->save();
$this->setFlashMessage('Profile updated successfully !', 'success', 'Profile');
return Redirect::route('profile-view');
} // public function update_details(ProfileUserDetailsRequest $request)
1) Can the reason be in ProfileUserDetailsRequest and how to deal this ?
My profile details editor works ok.
My route defined as :
Route::group(array('prefix' => 'profile', 'middleware' => ['auth', 'isVerified']), function(){
Route::post('edit-details-post', array(
'as' => 'profile-edit-details-post',
'uses' => 'ProfileController#update_details'
));
At first I tried PUT, but after that I tried POST - the same without results.
2) Can you advice some proper way of User Profile details checking on // 7. MODIFY PROFILE DETAILS PAGE BLOCK START step ?
MODIFIED BLOCK # 2 :
I tried patch method, but it does not work anyway.
I have debugging method in my app/Http/Controllers/ProfileController.php
public function update_details(ProfileUserDetailsRequest $request)
{
method and when test is run I see that it is not triggered.
I use the same update_details method updating my form in brauser and it work ok(I see debugging info too).
I suppose that could be csrf issue and in header of my test file I wrote:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use DB;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\WithoutMiddleware; // Prevent all middleware from being executed for this test class.
public function testProfilePage()
{
$csrf_token = csrf_token();
...
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->patch('profile/edit-details-post', [
'first_name' => 'Modified : ' . $newUser->first_name,
'last_name' => 'Modified : ' . $newUser->last_name,
'phone' => 'Modified : ' . $newUser->phone,
'website' => 'Modified : ' . $newUser->website,
// '_token' => $csrf_token / I TRIED TO UNCOMMENT THIS LINE TOO
]);
$response->assertStatus(205); // making this check I see that code 419 was returned
Can decision be to add in file app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
// ???
];
If in command line I run tests as
vendor/bin/phpunit tests/Feature/ProfilepageTest.php
What have I to add in except?
Thanks!
Other than the PATCH instead of POST following are my recommendations to test your code.
Instead of ProfileUserDetailsRequest try to use simple Request.
Try to log $request variable in your update function and check if the _token and _method are available, method should be PATCH and the request variables are posted correctly.
Make a model of user table and try to update the user with that model using
$user = User::find(Auth::user()->id);
…
$user->save();
Sessions are initiated with a middleware, i think if you are disabling the middleware, session will not work.
If you are using an IDE like Visual Studio Code to run your code then try using a debugger like xdebug. Place a breakpoint in your update_details method and see if it is getting to save and save is executing. If it is then we know save is not updating correctly.
It looks like what you are doing is correct according to the documentation for update:
https://laravel.com/docs/5.7/eloquent#updates example from docs below:
$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save();
Off the top of my head my only guess as to why it would fail is maybe getting the user off of the auth object causes problems. Take the id from the user in the auth object and use find() to grab the user then update its values and save and see if that works.

laravel 5.1 auth login returns an error

I'm trying to use auth()->login() in laravel 5.1 but it returns an error. Please see my code below:
$user = User::where('username', $username)->where('activation_code', $activation_code);
$not_activated_user = $user->where('status', 0)->where('confirmed', 0);
if($not_activated_user->count() == 1){
$not_activated_user->update([
'status' => 1,
'confirmed' => 1
]);
auth()->login($user->where('status', 1)->where('confirmed', 1));
}
I've also import use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; and implements AuthenticatableContract in my User model, but it still returns the same error. Why is that? I also tried to use ->get() in ->login(....->get()) to get the current user, but still same error.
Error:
Argument 1 passed to Illuminate\Auth\Guard::login() must implement interface Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\Database\Eloquent\Builder given
Try
$user = User::where('username', $username)->where('activation_code', $activation_code)->firstOrFail();
$user->update([
'status' => 1,
'confirmed' => 1
]);
auth()->login($user);
}
It's working now, I just called the User model again to select the current user :)

How to make field enum migration yii2

I make field ENUM and the result is error when I use yii migrate/up on CMD windows.
public function up()
{
$tableOptions = null;
if ($this->db->driverName === 'mysql') {
$tableOptions = 'CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE=InnoDB';
}
$this->createTable('{{%user_social_media}}', [
'social_media' => $this->ENUM('facebook', 'google', 'twitter', 'github'),
'id' => $this->primaryKey(),
'username' => $this->string(),
'user_id' => $this->integer(11),
'created_at' => $this->integer(11),
'updated_at' => $this->integer(11),
], $tableOptions);
}
There is no enum() method at the moment since not every DB is supporting ENUM fields. You can do it manually though:
'social_media' => "ENUM('facebook', 'google', 'twitter', 'github')",
Note:
This solution is for Mysql only
For related Postgresql content visit here
Actually the best way of working this and keeping your migrations clean would be by using some tool/helper like the one provided by the yii2mod team https://github.com/yii2mod/yii2-enum
this way you can build the enum functionality on code, works like a charm.
i.e. an enum for genderType
<?php
namespace common\models\enums;
use yii2mod\enum\helpers\BaseEnum;
/**
* Class GenderType
*
* #package yii2mod\settings\models\enumerables
*/
class GenderType extends BaseEnum
{
// add as many genders as you need
const MALE_TYPE = 'MALE';
const FEMALE_TYPE = 'FEMALE';
public static $list = [
self::MALE_TYPE => 'Male',
self::FEMALE_TYPE => 'Female',
];
}
Use the following methods to access your Enum:
createByName() - Creates a new type instance using the name of a
value.
getValueByName() - Returns the constant key by value(label)
createByValue() - Creates a new type instance using the value.
listData() - Returns the associative array with constants values and
labels
getLabel()- Returns the constant label by key
getConstantsByName() - Returns the list of constants (by name) for
this type.
getConstantsByValue() - Returns the list of constants (by
value) for this type.
isValidName() - Checks if a name is valid for
this type. isValidValue() - Checks if a value is valid for this type.

What's wrong with this Fluent NHibernate Configuration?

What's wrong with the following setup? The Where filter on the AutoPersistanceModel does not appear to be working and the table name convention does not appear to be working either. The error I'm evenually getting is "The element 'class' in namespace 'urn:nhibernate-mapping-2.2' has invalid child element 'property' in namespace 'urn:nhibernate-mapping-2.2'. List of possible elements expected: 'meta, jcs-cache, cache, id, composite-id' in namespace 'urn:nhibernate-mapping-2.2'." Here's my code:
public ISessionFactory BuildSessionFactory()
{
return Fluently.Configure()
.Database(
OracleConfiguration.Oracle9.ConnectionString(
c => c.FromConnectionStringWithKey("ConnectionString")))
.Mappings(m =>
{
m.AutoMappings.Add(GetAutoPersistanceModel);
m.FluentMappings.AddFromAssembly(Assembly.GetExecutingAssembly());
})
.BuildSessionFactory();
}
public AutoPersistenceModel GetAutoPersistanceModel()
{
return AutoPersistenceModel.MapEntitiesFromAssemblyOf<User>()
.Where(type => type.IsClass && !type.IsAbstract && type.Namespace == "Some.Namespace")
.ConventionDiscovery.Add<IConvention>(
Table.Is(x => "tbl" + x.EntityType.Name.Pluralize())
);
}
The exception is saying NHibernate has encountered a <property /> element first, which is invalid. The first element in an NHibernate hbm file should (nearly) always be an Id, so it seems the AutoPersistenceModel isn't finding your identifiers.
How are your Ids named in your entities? The AutoPersistenceModel expects them to be literally called Id, if they're anything different then it won't find them.
You can use the FindIdentity configuration option to override how the AutoPersistenceModel finds Ids, which can be useful if you're unable to modify your entities.
// if your Id is EntityId
.WithSetup(s =>
s.FindIdentity = property => property.DeclaredType.Name + "Id"
)
James is leading you correctly but his snippet is wrong.
.WithSetup(s=> s.FindIdentity = p => p.Name == "ID"));
Is what you're after! Replace "ID" with what ever your actual property is.