Mocking Laravel Eloquent models - how to set a public property with Mockery

Stefan Bogdanescu

Founder & Senior Architect · 2026-06-29

Laravel Company
# Mocking Laravel Eloquent Models: How to Set Public Properties with Mockery As developers working with the Laravel ecosystem, we frequently dive into unit and feature testing, often relying on mocking frameworks like Mockery to isolate our code. When dealing with Eloquent models—which are complex objects inheriting database logic—the process of mocking can sometimes introduce unexpected hurdles. A common sticking point arises when attempting to set public properties on a mock object created via Mockery. If you try to assign values directly, you often run into errors like the `BadMethodCallException` you encountered when trying to set `$mock->roles = 2;`. This usually signals that the way we are interacting with the mock doesn't align with how Mockery expects method calls to be structured on complex classes. This post will dive deep into why this happens and provide the correct, robust methods for setting state on mocked Eloquent models, ensuring your tests remain clean and reliable. ## The Root of the Problem: Methods vs. Properties in Mocking The core issue lies in how Mockery intercepts calls. When you mock a class, you are primarily telling Mockery what methods should be expected to be called (and what they should return). While PHP objects have public properties, Mockery often enforces a stricter contract when mocking classes derived from frameworks like Laravel Eloquent. When you try `$mock->roles = 2;`, Mockery might interpret this as an attempt to call a method named `setAttribute()` or similar internal mechanism that doesn't exist on the mock object itself, leading to the exception: `Method Mockery_0_User::setAttribute() does not exist on this mock object`. The solution is not necessarily about setting arbitrary public variables but about using Mockery’s expectation system to define the state the model *should* exhibit when methods are called. ## The Correct Approach: Using Expectation Setting Instead of trying to assign values directly to properties, we should leverage the expectations that Mockery provides to control the behavior of the mocked Eloquent model during the test execution. If your goal is to simulate a model instance with specific attributes for subsequent method calls, you define those attributes within the mock setup itself or ensure that any data retrieval methods (like `find()` or custom accessors) return the desired state. For setting simple public properties that are accessed outside of defined methods, the most reliable way to handle this is often through explicit expectation setting or by ensuring your test structure aligns with dependency injection principles. If you need to simulate a model instance that has specific data, focus on mocking the *behavior* rather than manipulating the mock's internal state directly via property assignment. Consider how you are using the `$mock` object in your test. If you are testing a service layer that interacts with this model, you usually don't need to manipulate the model instance's internal properties directly; you need to control what the model *returns* when queried. ## Practical Example: Simulating Eloquent Data Let's look at how we can correctly set expectations for an Eloquent model mock using Mockery. We will simulate a scenario where we expect a method like `hasRole()` to return specific data, which implies the object has certain properties. ```php use Mockery; use App\Models\User; // Assuming this is your Eloquent Model class UserRepositoryTest extends TestCase { public function test_user_with_specific_roles() { // 1. Create the mock instance $mock = Mockery::mock(User::class); // 2. Define expectations for methods (the primary focus of mocking) $mock->shouldReceive('hasRole') ->once() ->andReturn(true); // 3. If you need to simulate properties that methods rely on, // you often set them via expectation setup or ensure the object // behaves correctly when accessed by other code. // For simple property simulation, Mockery is best used to control // return values of methods rather than setting arbitrary internal state. // If you absolutely need a custom property accessor for testing purposes // in complex scenarios (which is less ideal), ensure the class supports it. // For typical Eloquent mocking, focus on method expectations: $mock->shouldReceive('id')->andReturn(101); // Example of setting expected return values // 4. Execute the test logic $this->assertTrue($mock->hasRole()); } } ``` Notice that we focused solely on defining what methods (`hasRole`, `id`) should return when called. This approach is more stable because it tests the contract of the object rather than manipulating its internal state, which avoids the conflict with Mockery's internal structure for Eloquent models. ## Conclusion Mocking Laravel Eloquent models requires shifting focus from directly setting public properties to defining explicit method expectations using Mockery. By adhering to this principle—testing the methods and return values that define the model's behavior—we ensure our tests are robust, independent of internal framework implementation details. Always aim to mock the *interface* your code uses, rather than attempting to manipulate the object's private or protected structure directly. For deeper insights into Laravel testing practices, exploring resources from [laravelcompany.com](https://laravelcompany.com) is highly recommended.