Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to mock environment files import in unit tests

In our angular app, we use environment files to load some config.

environment.ts

export const environment = {
  production: false,
  defaultLocale: 'en_US',
};

We then use it in one of our service:

import { environment } from '../../environments/environment';
import { TranslateService } from './translate.service';

@Injectable()
export class LocaleService {
  constructor(private translateService: TranslateService){}

  useDefaultLocaleAsLang(): void {
    const defaultLocale = environment.defaultLocale;
    this.translateService.setUsedLang(defaultLocale);
  }
}

So I use the values in environment file in a service method.

In our test file, we can of course Spy on the translateService:

translateService = jasmine.createSpyObj('translateService', ['setUsedLang']);

But I don't know how to mock the environment values in my testing file (in a beforeEach for example). Or even transform it, for testing purpose, to a Subject so I can change it and test different behaviors.

More generally speaking, how can you mock such imports values in tests to be sure not to use real values?

like image 885
BlackHoleGalaxy Avatar asked Mar 04 '18 02:03

BlackHoleGalaxy


People also ask

Should I mock everything in unit tests?

In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when it is impractical or impossible to incorporate a real object into a unit test. Mocking makes sense in a unit testing context.

How do I test environment variables?

On WindowsIn the command window that opens, enter echo %VARIABLE%. Replace VARIABLE with the name of the environment variable you set earlier. For example, to check if MARI_CACHE is set, enter echo %MARI_CACHE%. If the variable is set, its value is displayed in the command window.


2 Answers

You can't test/mock environment.ts. It is not part of Angular's DI system, it is a hard dependency on a file on the filesystem. Angular's compilation process is what enables swapping out the different environment.*.ts files under the hood when you do a build.

Angular's DI system is a typical Object Oriented approach for making parts of your application more testable and configurable.

My recommendation would be to take advantage of the DI system and use something like this sparingly

import { environment } from '../../environments/environment';

Instead do the same thing Angular does for any dependencies it wants you to be abstracted away from. Make a service that provides a seam between the environment.ts data and your application pieces.

It doesn't need to have any logic, it could simply pass through the properties of environment directly (therefore it wouldn't need tested itself).

Then update your services/components that depend on environment.ts and replace that dependency with the service. At test time you can mock it, sourcing the data from somewhere other than environment.ts

like image 173
seangwright Avatar answered Sep 19 '22 22:09

seangwright


Something like this worked for me:

it('should ...', () => {
  environment.defaultLocale = <location-to-test>; // e.g. 'en'

  const result = service.method();

  expect(result).toEqual(<expected-result>);
});
like image 22
R. de Ruijter Avatar answered Sep 21 '22 22:09

R. de Ruijter