【问题标题】:How to mock Pipe when testing Component测试组件时如何模拟管道
【发布时间】:2017-01-10 14:53:44
【问题描述】:

目前我正在覆盖提供者以使用这样的模拟服务:

beforeEach(inject([TestComponentBuilder], (tcb: TestComponentBuilder) => {
    tcb.overrideProviders(AddFieldToObjectDropdownComponent,
        [
             provide(ServiceA, { useClass: MockServiceA })),
             provide(ServiceB, { useClass: MockServiceB }))
        ])
    ...

我想对组件使用的管道做同样的事情。我试过了,provide(PipeA, { useClass: MockPipeA })provide(PipeA, { useValue: new MockPipeA() }) 但都没有工作。

【问题讨论】:

  • 当您在 4 个月内没有任何答案时,这并不乐观。你有想过这个吗?
  • @coblr 不,不幸的是,这对我来说不是一个高优先级问题,但我很快会使用新的测试 API 再次尝试,也许现在有一个解决方法。
  • 有什么解决办法吗?我试图不声明原始管道,而是创建一个模拟管道并声明它。但不知何故,管道渲染结果总是显示一个空字符串 ''
  • @harunurhan 你只需要模板中的管道吗?
  • 现在是 2019 年,仍然发生在我身上 :( 我期待“提供”的事情能够奏效。

标签: unit-testing angular angular2-testing angular2-pipe


【解决方案1】:

基于 @shohrukh 的回答,以下代码为您提供了一个可在 Angular 11/12 中工作的可重复使用的模拟管道:

import { Pipe, PipeTransform } from '@angular/core';

export function mockPipe(name: string): Pipe {
  const metadata: Pipe = {
    name
  };

  return Pipe(metadata)(
    class MockPipe implements PipeTransform {
      transform() {}
    }
  );
}

然后在你的测试中使用它:

TestBed.configureTestingModule({
  declarations: [
    MyComponent,
    mockPipe('myPipe')
  ],
  ...
}).compileComponents();

【讨论】:

    【解决方案2】:

    一种可能性是使用ng-mocks library 并像这样使用它:

    TestBed.configureTestingModule({
      declarations: [
        TestedComponent,
        MockPipe(ActualPipe, (...args) => args[0]),
      ]
    }).compileComponents();
    

    MockPipe 的第二个参数定义了转换函数为 args 数组返回的内容。

    【讨论】:

      【解决方案3】:

      你可以使用MockPipe npm 包,但是你需要像下面这样导入它。

      import { MockPipe } from 'mock-pipe';
      

      之后,您需要做的就是在提供程序中定义您的模拟管道..

      providers: [     
              {
                  provide: HighlightPipe,
                  useValue: MockPipe(HighlightPipe, () => 'mock')
              }
      ]
      

      就是这样。

      【讨论】:

      • 这在某一时刻可能是一个很好的解决方案,但该项目已经失效并且多年没有更新。它不适用于 Angular 11。
      【解决方案4】:

      将我的管道模拟成简单的类

      export class DateFormatPipeMock {
       transform() {
        return '29.06.2018 15:12';
       }
      }
      

      在我的规范文件中简单使用 useClass

      providers: [
        ...
        {provide: DateFormatPipe, useClass: DateFormatPipeMock}
        ...
      ]
      

      为我工作:-)

      【讨论】:

      • 您也可以创建一个合法管道并将其添加到您的 TestBed 下,就像您应该做的那样。
      【解决方案5】:

      如果你想要可重用的 util 函数来模拟管道,你可以试试这个选项:

      export function mockPipe(options: Pipe): Pipe {
          const metadata: Pipe = {
            name: options.name
          };
      
          return <any>Pipe(metadata)(class MockPipe {});
      }
      

      然后在 TestBed 声明数组中调用这个函数:

      TestBed.configureTestingModule({
          declarations: [
              SomeComponent,
              mockPipe({ name: 'myPipe' }),
              mockPipe({ name: 'myOtherPipe' })
          ],
          // ...
      }).compileComponents();
      

      【讨论】:

      • 这对我有用,但是谁能详细解释这个返回语句?
      • @Pommesloch 的 return 语句只是另一种写出 Dinistro 在另一个响应中所做的事情的方式。 &lt;any&gt;Pipe() 位被修饰在随后的类声明中。对于它的价值,这里是对 shohrukh 的响应的轻微增强,允许返回模拟管道数据。它可能会帮助您形象化。 ``` 导出函数 mockPipe(options: Pipe, mockReturn: any): Pipe { const metadata: Pipe = { name: options.name }; return Pipe(metadata)( class MockPipe implements PipeTransform { public transform = () => mockReturn; } ); } ```
      • 我在 Angular 11 上,这似乎不起作用。他们可能在内部改变了一些东西。我收到错误“TypeError:无法读取未定义的属性‘调用’”
      • @MattM 使用 Zack 上面的一条评论中的代码。但是如果原来的答案也调整一下就好了。
      【解决方案6】:

      您可以在TestBeddeclarations 中添加您的模拟管道:

      TestBed.configureTestingModule({
                   declarations: [
                       AppComponent,
                       MockPipe
                   ],
                  ...
      

      MockPipe 需要有带有原始名称的 @Pipe 装饰器。

      import {Pipe, PipeTransform} from '@angular/core';
      
      @Pipe({name: 'pipename'})
      class MockPipe implements PipeTransform {
          transform(value: number): number {
              //Do stuff here, if you want
              return value;
          }
      }
      

      【讨论】:

      • 有没有办法使用 Jasmine 监视模拟管道?我正在尝试模拟翻译管道并检查它是否使用正确的翻译键调用。
      • 模拟管道应该是您以该名称注册的唯一管道。我错误地导入了管道名称来源的模块。这阻止了我的 Mock 管道覆盖其原始实现。如果你在模拟管道,你的 Mock 应该是你注册的唯一实例,不要包括原始管道注册。
      • “不包括原始管道注册”eesh,如果 SUT 的导入超出您的控制范围,可能会很困难
      【解决方案7】:

      我们通常在模板中使用管道。这是模拟管道的方法。请注意,管道的名称必须与您正在模拟的管道相同。

      @Pipe({ name: 'myPipe' })
      class MyPipeMock implements PipeTransform {
        transform(param) {
          console.log('mocking');
          return true;
        }
      }
      

      如果您在声明的组件模板中使用管道,则需要在配置您的 TestingModule 时包含管道。

      【讨论】:

      • 你如何用这个配置测试?
      【解决方案8】:

      要存根管道,请使用 Dinistro 的答案。要监视管道,您可以通过以下方式对其进行补充:

      let pipeSpy: jasmine.Spy;
      
      beforeEach(() => {
          TestBed.configureTestingModule...
      
          pipeSpy = spyOn(MockPipe.prototype, 'transform');
      };
      
      it('should do whatever', () => {
          doYourStuff();
      
          expect(pipeSpy).toHaveBeenCalled();
      }
      

      【讨论】:

      • 另请注意:如果您不需要 MockPipe,可以在原始管道上 spyOn
      猜你喜欢
      • 2017-11-16
      • 2018-08-09
      • 1970-01-01
      • 1970-01-01
      • 2018-09-28
      • 1970-01-01
      • 2016-06-28
      • 2020-11-30
      • 1970-01-01
      相关资源
      最近更新 更多