I'm trying to test a plain class
(not a component) in Angular which has a service dependency and a separate constructor argument. I've mirrored the docs for component testing with a dependency, but I get the following error:
Unexpected value 'MyClass' imported by the module 'DynamicTestModule'. Please add a @NgModule annotation.
my-service.service.ts
:
@Injectable({
providedIn: 'root',
})
export class MyService { ... }
my-class.ts
:
import { inject } from '@angular/core';
import { MyService } from './my-service.service';
export class MyClass {
private _myService: MyService = inject(MyService);
private _name: string;
constructor(name: string) {
this._name = name;
}
}
my-class.spec.ts
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyService } from './my-service.service';
import { MyClass } from './my-class';
describe('MyClass', () => {
let myClass: MyClass;
let mockMyService: Partial<MyService>;
let fixture: ComponentFixture<MyClass>;
beforeEach(() => {
mockMyService = {};
TestBed.configureTestingModule({
imports: [MyClass],
providers: [{ provide: MyService, useValue: mockMyService }],
});
fixture = TestBed.createComponent(MyClass); // causes error
myClass = fixture.componentInstance;
TestBed.inject(MyService);
});
it('should create', () => {
expect(myClass).toBeTruthy();
});
});
updated my-class.spec.ts
import { MyClass } from './my-class';
describe('MyClass', () => {
let myClass: MyClass;
beforeEach(() => {
myClass = new MyClass('someName');
});
it('should create', () => {
expect(myClass).toBeTruthy();
});
});
How can I test this plain class with the service dependency?
Since you are using MyClass
as a component, you need the @Component
decorator to initialize it as a component so we can create a dummy class with the component decorator and inherit all the contents of MyClass
into the testing class MyClassMocked
.
Since you are using MyClass
in the imports array, that means, it must be standalone: true
so I have added that, if you do not want standalone as true
then you need to add MyClass
to the declarations
array instead!
Also we need to update the class MyClass
to MyClassMocked
wherever it's used as a type:
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { MyService } from './my-service.service';
import { MyClass } from './my-class';
import { inject, Component } from '@angular/core';
import { MyService } from './my-service.service';
@Component({ selector: 'my-class', standalone: true, template: '' })
export class MyClassMocked extends MyClass {
constructor() { super(); }
}
describe('MyClass', () => {
let myClass: MyClassMocked;
let mockMyService: Partial<MyService>;
let fixture: ComponentFixture<MyClassMocked>;
beforeEach(() => {
mockMyService = {};
TestBed.configureTestingModule({
imports: [MyClassMocked],
providers: [{ provide: MyService, useValue: mockMyService }],
});
fixture = TestBed.createComponent(MyClassMocked); // should work!
myClass = fixture.componentInstance;
TestBed.inject(MyService);
});
it('should create', () => {
expect(myClass).toBeTruthy();
});
});