66
77use Hyperf \Redis \Pool \PoolFactory ;
88use Hyperf \Redis \Pool \RedisPool ;
9- use Hyperf \Redis \RedisFactory ;
9+ use Hyperf \Redis \RedisFactory as HyperfRedisFactory ;
1010use Hypervel \Cache \RedisStore ;
1111use Hypervel \Redis \RedisConnection ;
12+ use Hypervel \Redis \RedisFactory as HypervelRedisFactory ;
13+ use Hypervel \Redis \RedisProxy ;
14+ use Hypervel \Tests \Redis \Stub \FakeRedisClient ;
1215use Mockery as m ;
1316use Redis ;
1417use RedisCluster ;
1518
1619/**
1720 * Shared test infrastructure for Redis cache operation tests.
1821 *
19- * Provides helper methods for mocking Redis connections, pool factories,
20- * and creating RedisStore instances for testing.
22+ * Provides helper methods for mocking Redis connections and creating
23+ * RedisStore instances for testing. Requires tests to extend
24+ * `Hypervel\Testbench\TestCase` for proper container setup.
2125 *
2226 * ## Usage Examples
2327 *
@@ -134,6 +138,28 @@ protected function createPoolFactory(
134138 return $ poolFactory ;
135139 }
136140
141+ /**
142+ * Register a RedisFactory mock in the container.
143+ *
144+ * This sets up the mock that StoreContext::withConnection() uses to get
145+ * connections via ApplicationContext::getContainer().
146+ */
147+ protected function registerRedisFactoryMock (
148+ m \MockInterface |RedisConnection $ connection ,
149+ string $ connectionName = 'default '
150+ ): void {
151+ $ redisProxy = m::mock (RedisProxy::class);
152+ $ redisProxy ->shouldReceive ('withConnection ' )
153+ ->andReturnUsing (fn (callable $ callback ) => $ callback ($ connection ));
154+
155+ $ redisFactory = m::mock (HypervelRedisFactory::class);
156+ $ redisFactory ->shouldReceive ('get ' )
157+ ->with ($ connectionName )
158+ ->andReturn ($ redisProxy );
159+
160+ $ this ->instance (HypervelRedisFactory::class, $ redisFactory );
161+ }
162+
137163 /**
138164 * Create a RedisStore with a mocked connection.
139165 *
@@ -148,8 +174,11 @@ protected function createStore(
148174 string $ connectionName = 'default ' ,
149175 ?string $ tagMode = null ,
150176 ): RedisStore {
177+ // Register RedisFactory mock for StoreContext::withConnection()
178+ $ this ->registerRedisFactoryMock ($ connection , $ connectionName );
179+
151180 $ store = new RedisStore (
152- m::mock (RedisFactory ::class),
181+ m::mock (HyperfRedisFactory ::class),
153182 $ prefix ,
154183 $ connectionName ,
155184 $ this ->createPoolFactory ($ connection , $ connectionName )
@@ -189,8 +218,11 @@ protected function createClusterStore(
189218 $ connection = $ this ->mockClusterConnection ();
190219 $ clusterClient = $ connection ->_mockClient ;
191220
221+ // Register RedisFactory mock for StoreContext::withConnection()
222+ $ this ->registerRedisFactoryMock ($ connection , $ connectionName );
223+
192224 $ store = new RedisStore (
193- m::mock (RedisFactory ::class),
225+ m::mock (HyperfRedisFactory ::class),
194226 $ prefix ,
195227 $ connectionName ,
196228 $ this ->createPoolFactory ($ connection , $ connectionName )
@@ -202,4 +234,43 @@ protected function createClusterStore(
202234
203235 return [$ store , $ clusterClient , $ connection ];
204236 }
237+
238+ /**
239+ * Create a RedisStore with a FakeRedisClient.
240+ *
241+ * Use this for tests that need proper reference parameter handling (e.g., &$iterator
242+ * in SCAN/HSCAN/ZSCAN operations) which Mockery cannot properly propagate.
243+ *
244+ * @param FakeRedisClient $fakeClient Pre-configured fake client with expected responses
245+ * @param string $prefix Cache key prefix
246+ * @param string $connectionName Redis connection name
247+ * @param null|string $tagMode Optional tag mode ('any' or 'all')
248+ */
249+ protected function createStoreWithFakeClient (
250+ FakeRedisClient $ fakeClient ,
251+ string $ prefix = 'prefix: ' ,
252+ string $ connectionName = 'default ' ,
253+ ?string $ tagMode = null ,
254+ ): RedisStore {
255+ $ connection = m::mock (RedisConnection::class);
256+ $ connection ->shouldReceive ('release ' )->zeroOrMoreTimes ();
257+ $ connection ->shouldReceive ('serialized ' )->andReturn (false )->byDefault ();
258+ $ connection ->shouldReceive ('client ' )->andReturn ($ fakeClient )->byDefault ();
259+
260+ // Register RedisFactory mock for StoreContext::withConnection()
261+ $ this ->registerRedisFactoryMock ($ connection , $ connectionName );
262+
263+ $ store = new RedisStore (
264+ m::mock (HyperfRedisFactory::class),
265+ $ prefix ,
266+ $ connectionName ,
267+ $ this ->createPoolFactory ($ connection , $ connectionName )
268+ );
269+
270+ if ($ tagMode !== null ) {
271+ $ store ->setTagMode ($ tagMode );
272+ }
273+
274+ return $ store ;
275+ }
205276}
0 commit comments