ignaciodev's avatar

How to test query methods from traits

I have the following trait that I want to use on some of my models:

trait HasHashedID
{
    public static function findByHashOrFail($hash)
    {
        $id = dehash($hash);
        return self::findOrFail($id);
    }
}

What would be the correct way to test this?

0 likes
4 replies
tisuchi's avatar

@ignaciodev Here's an example of how you could test the findByHashOrFail() method in the HasHashedID trait:

  1. Create a test model that uses the trait:
use HasHashedID;
class TestModel extends Model {
    use HasHashedID;
}
  1. Create a test case for the trait:
class HasHashedIDTest extends TestCase
{
    public function test_find_by_hash_or_fail()
    {
        // Create a test model instance and save it to the database
        $model = new TestModel();
        $model->save();
        $hash = hash($model->id);

        // Test finding the model by hash
        $foundModel = TestModel::findByHashOrFail($hash);
        $this->assertEquals($model->id, $foundModel->id);

        // Test finding non-existent model by hash
        $this->expectException(ModelNotFoundException::class);
        TestModel::findByHashOrFail('invalid-hash');
    }
}
  1. In the first test, you create a new instance of the TestModel, save it to the database, and then use the findByHashOrFail() method to retrieve it by hash. Then you assert that the id of the found model is equal to the id of the original model.

  2. In the second test, you use an invalid hash, so the method should throw a ModelNotFoundException. You use the expectException() method to assert that the correct exception is thrown.

Note that the dehash() method that you are using inside the trait is not provided in this example, but it should be defined elsewhere in your code and you can use it accordingly.

1 like
ignaciodev's avatar

@tisuchi Thank you for such detailed answer!!

If I use a test model, $model->save() throws a QueryException (I'm guessing because the table does not exist). If I use one of my existing models (which I'd rather not use, since I am trying to unit test my trait) this error is not thrown, and the test passes.

I tried solving by doing this (like they do on Spatie) but throws a There is no active transaction error:

$this->app['db']->connection()->getSchemaBuilder()->create('test_models', function (Blueprint $table) {
    $table->id();
    $table->timestamps();
});

$testModel = new class extends Model {
    use HasHashedID;
    protected $table = 'test_models';
};

$model = new $testModel();
$model->save();

Please or to participate in this conversation.