How do I mock Models when testing? |
Trying to add tests to my CI4 library but I cannot understand how to mock Models.
I want to test my CredlyProvider library. This library contains code that use Tangix\VirtualTester\Models\UserModel to provide all the logic needed to lookup a user's information: PHP Code: $user = UserModel::factory() For testing purposes, using the full UserModel would require tons of database tables and data to be seeded and is not viable situation. Instead I planned to create a simple substitute Model for testing simply return a static known data that can be used. I put this in ./tests/_support/Mocks/UserModel.php: PHP Code: <?php And then trying to run the following in the test: PHP Code: public function test05IssueBadge() Unfortunately this doesn't work, the Tangix\VirtualTester\Models\UserModel is used instead of the mocked one. I have tried moving the injectMock() call to setUp() and other places in the test file, but so far no go. Namespaces seems to be setup correct because $model contains the mocked version. Could anyone share some info on how they go about testing Libraries with mocked Models? Thanks, /Mattias
Your mocking approach generally looks good to me. The issue is that you aren’t using Factories for your instantiation. Instead of `return new UserModel();` you should get the shared instance from factories, e.g. with the helper method:
return model(self::class); Factories is intended to be a central factory manager so having UserModel::factory() is a bit redundant. I would normally handle your original call like this: $user = model(UserModel::class)->find($userID); If you don’t like the helper method and would prefer to be explicit about the fact that this is a factory then you can use the class directly: Factories::model(UserModel::class)
Thanks MGatner - that works!
Never used the model() call, that's why I "invented" my own factory(), but I guess I should rethink that approach now. Only object would be that it looks a bit ugly and redundant use of "model": PHP Code: $user = model(UserModel::class)->find(28); Thanks again!
I like your model factory approach! You could keep using it that way and even expand it by placing it on a parent BaseModel and have it do something like this:
PHP Code: public static function factory(): static That way you could always access your shared factory instance but still use the actual model class you are after: PHP Code: UserModel::factory()->find(1); (06-19-2022, 03:22 AM)MGatner Wrote: I like your model factory approach! You could keep using it that way and even expand it by placing it on a parent BaseModel and have it do something like this: Thanks, I actually already did exactly that - I don't compare myself with giants like yourself, but great minds think alike ;-) This was a good refresher in self, static and parent BTW... |
Welcome Guest, Not a member yet? Register Sign In |