setNotifyConfig('notify_email_enable', '0'); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('渠道未启用'); (new EmailChannel())->send( ['channel' => 'email', 'target_addr' => 'disabled@test.com', 'status' => 0], ['id' => 1, 'scene' => 'common', 'title' => '标题', 'content' => '内容'] ); } // ========================================================================= // 2. SmsChannel 骨架恒成功 // ========================================================================= public function test_sms_channel_send_returns_true(): void { $this->assertTrue((new SmsChannel())->send( ['channel' => 'sms', 'target_addr' => '13800138000', 'status' => 0], ['id' => 1, 'scene' => 'common', 'title' => '标题', 'content' => '内容'] )); } // ========================================================================= // 3. WechatChannel 骨架恒成功 // ========================================================================= public function test_wechat_channel_send_returns_true(): void { $this->assertTrue((new WechatChannel())->send( ['channel' => 'wechat', 'target_addr' => 'openid_demo', 'status' => 0], ['id' => 1, 'scene' => 'common', 'title' => '标题', 'content' => '内容'] )); } // ========================================================================= // 4. name() 契约与 channels() 映射一致 // ========================================================================= public function test_channel_names_match_service_mapping(): void { $this->assertSame('email', EmailChannel::name()); $this->assertSame('sms', SmsChannel::name()); $this->assertSame('wechat', WechatChannel::name()); $channels = NoticeService::channels(); $this->assertSame(EmailChannel::class, $channels['email']); $this->assertSame(SmsChannel::class, $channels['sms']); $this->assertSame(WechatChannel::class, $channels['wechat']); } // ========================================================================= // fixture 工厂(事务内运行,tearDown 自动回滚;缓存显式清理) // ========================================================================= /** * 写 notify 组配置行并清 sysconfig 缓存. * * sysconfig 缓存不受事务回滚影响:必须显式清 tag 才能让后续读取 * 看到事务内的新值(value='0' 因 empty('0') 恒不写缓存,但清理是 * 防御后续用例被前序非 '0' 缓存值污染的统一口径)。 */ private function setNotifyConfig(string $name, string $value): void { Db::name('system_config')->insert([ 'name' => $name, 'group' => 'notify', 'value' => $value, 'remark' => 'NoticeChannelTest fixture', 'sort' => 100, 'create_time' => time(), 'update_time' => time(), ]); $this->touchedSysconfig = true; Cache::tag('sysconfig')->clear(); } protected function tearDown(): void { if ($this->touchedSysconfig) { Cache::tag('sysconfig')->clear(); } parent::tearDown(); } }