【问题标题】:Angular2 Unit Testing ServicesAngular2 单元测试服务
【发布时间】:2018-01-11 14:18:28
【问题描述】:

我是单元测试的新手,想知道如何对依赖于一个服务的组件进行单元测试,而该组件又依赖于许多其他服务。下面是我的初始设置。

beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [TestComp],
      providers: [TestService]
    }).compileComponents();
  }));

但是这样做,它无法找到它所依赖的其他服务。然后我会像这样提供其他服务。但随着这些服务使用其他服务等,它会继续增长。

beforeEach(async(() => {
        TestBed.configureTestingModule({
          declarations: [TestComp],
          providers: [TestService, TestServiceDependencyService, TestServiceDependecyService2]
        }).compileComponents();
      }));

我对另一个依赖于服务的单元测试做的一件事是创建一个像这样的模拟服务。

 beforeEach(async(() => {
    TestBed.configureTestingModule({
      declarations: [TestComponent],
    }).overrideComponent(TestComponent, {
      set: {
        providers: [
          { provide: TestService, useClass: MockTestService},
        ]
      }
    })
      .compileComponents();
  }));

现在这里的模拟服务更容易了,因为没有太多功能,而且我能够“模拟”返回值。

在这个新组件中 - 模拟正确的返回值要困难得多。在这种情况下我该怎么办?

【问题讨论】:

  • 是的,使用模拟服务。目前尚不清楚您当前组件的具体问题是什么;您实际上并没有表现出预期的行为,也没有在测试中尝试将其消除。
  • 我会嘲笑什么?嘲笑所有服务似乎有点不对劲?现在没有嘲笑,只是提供服务,我得到一个 service.method() is not a function
  • “我要模拟什么?” - 您正在测试的服务所依赖的其他服务。 “模拟所有服务似乎有点不对劲?” - 这是一个问题吗?为什么这看起来不对?关键是您要隔离那个服务的行为。 “现在...” - 然后给minimal reproducible example。这个问题太模糊,无法正确回答,因此回答平庸。

标签: angular unit-testing jasmine


【解决方案1】:

这是我的方法,所以不要把我的话当作普遍的答案,而是作为一种快速简便的方法来做到这一点。

首先,让我告诉你,这是第一次,你做得很好。没错,你需要模拟你的依赖项

我所做的是创建模拟 values 而不是类(就像您所做的那样)。我将它们放在一个文件中,这样无论您要测试的组件是什么,每个模拟都始终相同。

这是一个例子:

export const myMockedService = {};

正如你所做的那样,你需要提供它(导入它的操作符只是稍微改变了一点):

TestBed.configureTestingModule({
  declarations: [TestComp],
  providers: [{ provide: MyService, useValue: myMockedService }]
}).compileComponents();

现在您的服务已被模拟,您可以开始了。

当您开始测试时,您的组件将尝试调用您服务的某些方法。由于您的模拟没有任何内容,这将引发错误,说明该方法丢失(为了我的示例,假设auth()

在这种情况下,您只需将其添加到您的模拟中:

export const myMockedService = {
  auth: () => null
};

现在你的方法被嘲笑了!由于您是在测试一个组件,而不是您的服务,因此您不需要实现一个完整的模拟,一个虚拟模拟就可以了。

之后,你仍然会收到一些错误,例如在 HTTP 调用的情况下出现can't subscribe to undefined

发生这种情况是因为,如您所见,服务返回 nothing

我想你已经猜到了,但无论如何:

export const myMockedService = {
  auth: () => Observable.of(null)
};

现在你的服务返回一个 Observable !在某些情况下,尤其是 HTTP 调用,您需要模拟返回,以便您可以测试组件中的函数的作用。

再次:

export const myMockedService = {
  auth: () => Observable.of(new User('Pickle', 'RIIIIIIIIIIICK'))
};

您现在有了一个完全模拟的身份验证方法!

奖金

您可以导入RouterTestingModuleHttpTestingModule 来模拟您的路由模块或http 模块。这将消除这两个模块中有关依赖项的所有错误。

【讨论】:

  • 如果你需要更多的解释,尽管问,我很乐意给你!
  • 感谢详细的回复!我想我不确定我应该在单元测试中测试什么。我正在测试的东西是变量中的正确值正确显示在 gui 端,所有内容都正确更新,以及应该显示什么显示,不应该显示的不显示。我的方法有点正确吗?现在这个组件的问题是,在确定应该或不显示什么时依赖于依赖于其他服务的这个服务。在“模拟”这个服务时,我是否模拟了所有可能的返回值?
  • 再说一次,我的意见,但我认为单元测试应该测试你的函数的逻辑。如果您想测试按钮点击、正确的 UI 显示等,您应该使用 e2e(端到端)测试。但是你当然可以在你的单元测试中做任何事情!
【解决方案2】:

就单元测试而言,您只需测试特定的组件/服务文件,您必须模拟它的任何其他依赖项,这就是要走的路。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-31
    • 2016-12-14
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    相关资源
    最近更新 更多