PHPUnit test dealing 14 unique playing cards
So I have been stumped by this problem for a while now. I am creating a Pai Gow Poker website (for those of you who don't know what Pai Gow is, it's a game where two combined decks are shuffled. Seven cards are dealt to the player and seven for the dealer. The player and dealer make a high and low hand (the high out of 5 cards and the low 2), For more details look on the game's Wikipedia page.
I am writing a PHPUnit test which ensures that the 14 cards dealt are unique and all cards dealt for both hands contain no duplicates. When I run my PHHPUnit test in my Vagrantvo, I get the following error:
``
- Tests\Feature\GameTest::test_both_hands_have_unique_cards ErrorException: Object of class Closure could not be converted to string
/home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Support/Str.php:300 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Support/Str.php:281 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/QueryException.php:56 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/QueryException.php:39 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Connection.php:648 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Connection.php:607 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Connection.php:450 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Connection.php:404 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Query/Processors/Processor.php:32 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Query/Builder.php:2131 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Builder.php:1236 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:677 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:642 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:511 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:148 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Support/Collection.php:260 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:149 /home/vagrant/Code/bitpaigow/vendor/laravel/framework/src/Illuminate/Database/Eloquent/FactoryBuilder.php:131 /home/vagrant/Code/bitpaigow/tests/Feature/GameTest.php:32``
I am using a ```for loop incrementing by 2 to select every second card dealt by the model factory. I elected to use this method because only from what I know so far, only 1 method can be used to generate models. I used static variables in the method, but I am not sure if this is the best way to go. I tried using faker to generate random playing cards, but PHPUnit said the maximum amount of retries exceeded and no unique cards were found. Here is the current code I have
GameTest.php
namespace Tests\Feature;
use Tests\TestCase;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class GameTest extends TestCase
{
use DatabaseMigrations;
/**
* A basic test example.
*
* @return void
*/
public function setUp() {
parent::setUp();
$this->game = factory('App\Game')->create();
$this->user = factory('App\User')->create();
$this->hand = factory('App\Hand')->create(['player' => 1, 'user_id' => $this->user->id]);
}
public function test_both_hands_have_unique_cards()
{
$cards = factory('App\Card', 14)->create(['game_id' => $this->game->id, 'hand_id' => $this->hand->id]);
for($i =0; $i <= 13; $i+=2) {
$this->assertTrue(($cards[$i]->suite == $cards[$i++]->suite) && ($cards[$i]->value == $cards[$i++]->value));
}
}
}
ModelFactory.php
/*
|--------------------------------------------------------------------------
| Model Factories
|--------------------------------------------------------------------------
|
| Here you may define all of your model factories. Model factories give
| you a convenient way to create models for testing and seeding your
| database. Just tell the factory how a default model should look.
|
*/
/** @var \Illuminate\Database\Eloquent\Factory $factory */
$factory->define(App\User::class, function (Faker\Generator $faker) {
static $password;
return [
'id' => $faker->randomNumber(3),
'name' => $faker->name,
'email' => $faker->unique()->safeEmail,
'password' => $password ?: $password = bcrypt('secret'),
'remember_token' => str_random(10),
];
});
$factory->define(App\Hand::class, function(Faker\Generator $faker) {
return [
'user_id' => function() {
return factory('App\User')->create()->id;
},
'game_id' => function() {
return factory('App\Game')->create()->id;
},
];
});
$factory->define(App\Game::class, function(Faker\Generator $faker) {
return ['user_id' => function () {
return factory('App\User')->create()->id;
}];
});
$factory->define(App\Card::class, function(Faker\Generator $faker) {
static $cards = null;
$cards = ['H' => range(1,13),
'D' => range(1,13),
'S' => range(1,13),
'C' => range(1,13)];
$pick_suite = ['H', 'D', 'S', 'C'];
$selected_suite = $pick_suite[rand(1,3)];
$selected_value = rand(0, count($cards[$selected_suite]));
// select card
$selected_card = $cards[$selected_suite][$selected_value];
// unset form array
unset($cards[$selected_suite][$selected_value]);
return ['player_hand' =>
['hand_id' => function () {
return factory('App\Hand')->create()->id();
},
'suite' => $selected_suite,
'value' => $selected_value,
'player' => function() {
static $player = false;
if($player) {
$player = false;
return true;
} else {
$player = true;
return false;
}
},
]];
});
Please or to participate in this conversation.