You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Jasmine测试中Mock Angular环境变量以测试多环境逻辑?

How to Mock the environment File in Angular for Testing Production/Development Scenarios

我来帮你解决Angular测试中mock environment的问题!针对你服务里依赖environment.production的两种场景,这里有几种实用的方案,你可以根据自己的测试框架和项目情况选择:

方法1:使用jest.mock(适合Jest测试框架)

如果你的项目用Jest做测试,这是最直接的方案——Jest支持直接mock整个模块,还能在不同测试用例里灵活切换production的值:

// 先mock整个environment模块,设置默认值
jest.mock('../environment', () => ({
  environment: {
    production: false
  }
}));

describe('MyService', () => {
  let service: MyService;
  // 引用mock的environment,方便后续修改
  const mockEnvironment = jest.requireMock('../environment').environment;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [MyService]
    });
    service = TestBed.inject(MyService);
  });

  it('should execute non-production logic when not in production', () => {
    mockEnvironment.production = false;
    service.something();
    // 在这里添加你的断言,比如验证非生产环境的代码逻辑是否执行
  });

  it('should execute production logic when in production', () => {
    mockEnvironment.production = true;
    service.something();
    // 断言生产环境的代码逻辑是否正常执行
  });
});

方法2:通过依赖注入封装(Angular最佳实践)

直接导入environment会让服务和环境配置紧耦合,更好的方式是用注入令牌封装环境配置,这样测试时mock会更优雅:

步骤1:创建环境注入令牌

// environment.provider.ts
import { InjectionToken } from '@angular/core';
import { environment } from '../environment';

// 创建注入令牌,把environment作为可注入的依赖
export const ENVIRONMENT = new InjectionToken('Environment', {
  providedIn: 'root',
  factory: () => environment
});

步骤2:修改服务,通过注入获取环境配置

import { Inject, Injectable } from '@angular/core';
import { ENVIRONMENT } from './environment.provider';

@Injectable({ providedIn: 'root' })
export class MyService {
  // 通过注入获取environment,不再直接导入
  constructor(@Inject(ENVIRONMENT) private environment: typeof environment) {}

  public something() {
    if(this.environment.production) {
      // do stuff
    } else {
      // do something else
    }
  }
}

步骤3:测试时mock注入的ENVIRONMENT

describe('MyService', () => {
  let service: MyService;

  beforeEach(() => {
    TestBed.configureTestingModule({
      providers: [
        MyService,
        // 默认mock为非生产环境
        { provide: ENVIRONMENT, useValue: { production: false } }
      ]
    });
    service = TestBed.inject(MyService);
  });

  it('should run non-production code', () => {
    const env = TestBed.inject(ENVIRONMENT);
    env.production = false;
    service.something();
    // 添加断言验证逻辑
  });

  it('should run production code', () => {
    // 覆盖provider,切换为生产环境配置
    TestBed.overrideProvider(ENVIRONMENT, { useValue: { production: true } });
    // 重新获取服务,使用新的配置
    service = TestBed.inject(MyService);
    service.something();
    // 添加断言验证逻辑
  });
});

方法3:使用ts-mock-imports(适合Karma/Jasmine)

如果你的项目用Angular CLI默认的Karma/Jasmine测试框架,Jasmine没有直接mock模块的功能,你可以用ts-mock-imports库来实现:

首先安装依赖:

npm install ts-mock-imports --save-dev

然后在测试文件中使用:

import { MockManager } from 'ts-mock-imports';
import * as environmentModule from '../environment';
import { MyService } from './my.service';

describe('MyService', () => {
  let service: MyService;
  let environmentMock: MockManager<typeof environmentModule>;

  beforeEach(() => {
    // 创建environment模块的mock
    environmentMock = MockManager.mockModule(environmentModule, {
      environment: { production: false }
    });

    TestBed.configureTestingModule({
      providers: [MyService]
    });
    service = TestBed.inject(MyService);
  });

  afterEach(() => {
    // 测试结束后重置mock,避免影响其他用例
    environmentMock.restore();
  });

  it('should handle non-production environment', () => {
    environmentMock.setMock({ environment: { production: false } });
    service.something();
    // 添加断言
  });

  it('should handle production environment', () => {
    environmentMock.setMock({ environment: { production: true } });
    service.something();
    // 添加断言
  });
});

内容的提问来源于stack exchange,提问作者kodeaben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:22:31