具有瞬态依赖性的 Aurelia 测试组件从不使用模拟

Aurelia testing components with transient dependencies never uses a mock

我们正在使用此处定义的 aurelia 组件测试(开玩笑):https://aurelia.io/docs/testing/components#testing-a-custom-element

我们正在测试的组件具有瞬态依赖性。我们正在为这个依赖创建一个 mock,但是当我们 运行 使用 au jest 进行测试时, 真实的总是被 DI 容器注入,而不是 mock.

这是临时服务:

import { transient } from "aurelia-framework";

@transient()
export class ItemService {
  constructor() {
  }

  getItems(): void {
    console.log('real item service');
  }
}

这是 'Mock' 服务(我们也尝试过使用 jest mocks 但我们得到了相同的结果):

import { transient } from "aurelia-dependency-injection";

@transient()
export class MockItemService{
  getItems():void {
    console.log('mock item service');
  }
}

这是被测组件:

import {ItemService} from "../services/item-service";
import { autoinject } from "aurelia-dependency-injection";

@autoinject()
export class TestElement {
  constructor(private _itemService: ItemService) {

  }

  attached(): void {
    this._itemService.getItems();
  }
}

这是规范文件:

import {TestElement} from "../../src/resources/elements/test-element";
import {ComponentTester, StageComponent} from "aurelia-testing";
import {ItemService} from "../../src/resources/services/item-service";
import {MockItemService} from "./mock-item-service";
import {bootstrap} from "aurelia-bootstrapper";

describe('test element', () => {
  let testElement;
  const path: string = '../../src/resources/elements/test-element';

  beforeEach(() => {
    testElement = StageComponent.withResources(path).inView(`<test-element></test-element>`);

    testElement.bootstrap(aurelia => {
      aurelia.use.standardConfiguration();
      aurelia.container.registerTransient(ItemService, MockItemService);
    });
  });

  afterEach(() => {
    testElement.dispose();
  });

  it('should call mock item service', async() => {
    await testElement.create(bootstrap);
    expect(testElement).toBeTruthy();
  })
});

但每次测试都是 运行,控制台会注销真实服务而不是模拟服务。我已经将其追溯到 Container.prototype.get 函数中的 aurelia-dependency-injection.js 。问题似乎与这部分代码有关:

var registration = aureliaMetadata.metadata.get(aureliaMetadata.metadata.registration, key);
if (registration === undefined) {
    return this.parent._get(key);
} 

注册对象似乎有点奇怪,如果未定义,代码将工作,因为正确的依赖项已在父级上注册,并且它将获得模拟依赖项。但是,它不是未定义的,因此它在这一行的 DI 容器中注册了真正的服务:

return registration.registerResolver(this, key, key).get(this, key);

注册对象如下所示:

registration = TransientRegistration {_key = undefined}

这是 aurelia 中的错误还是我的操作有问题?

非常感谢

p.s。 GitHub 回购这里复制问题:https://github.com/Magrangs/aurelia-transient-dependency-issue

p.p.s 分叉了 DI 容器存储库并添加了一个快速修复程序,它可以解决我的特定问题,但不确定会产生什么连锁反应。如果aurelia团队的成员可以检查一下,那就太好了:

https://github.com/Magrangs/dependency-injection/commit/56c7d96a496e76f330a1fc3f9c4d62700b9ed596

在与 Rob Eisenberg 就此问题进行交谈后,有一个解决此问题的方法。首先删除 class 上的 @transient 装饰器,然后在您的应用启动时(通常是 main.ts)将 class 注册为瞬态。

在此处查看主题: https://github.com/Magrangs/dependency-injection/commit/56c7d96a496e76f330a1fc3f9c4d62700b9ed596

我还更新了上面发布的回购协议:https://github.com/Magrangs/aurelia-transient-dependency-issue

包括修复。

希望这能帮助面临同样问题的任何其他开发者。