Javascript 角度7测试公共方法依赖于私人方法

Javascript 角度7测试公共方法依赖于私人方法,javascript,angular,jasmine,Javascript,Angular,Jasmine,我使用angular 7.1和Jasmine来测试我的组件。我正试着写一些测试,但这个似乎对我来说太多了 我尝试测试的简化类: import { HttpClient } from '@angular/common/http'; @Component({ selector: 'a', templateUrl: './a.html', styleUrls: ['./a.scss'] } export class A implements OnInit { constructor(

我使用angular 7.1和Jasmine来测试我的组件。我正试着写一些测试,但这个似乎对我来说太多了

我尝试测试的简化类:

import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'a',
  templateUrl: './a.html',
  styleUrls: ['./a.scss']
}
export class A implements OnInit {
  constructor(private http: HttpClient) {}
  private privateState: State;
  public publicState: State2;      

  ngOnInit() {
      this.http.get(this.GetUrl()).subscribe((x) => {
      this.privateState = x['whatever'];
    });
  }

  private hiddenComplexFunction() {
    this.publicState = this.privateState.something;
  }

  public testedFunction() {
    //someComplex Code
    this.hiddenComplexFunction();
  }
}
我所尝试的:

  • 我试图设置私有变量,如
    A.['privateState']
    ,但没有成功
  • 我尝试使用SpyOn http get,但也遇到了同样的问题,即必须设置私有属性
  • 我试图使用HttpClientTestingModule,但我遇到了与前一点相同的问题
  • 最后,我尝试使privateState受到保护,并通过以下方式进行测试:

    import { HttpClientTestingModule } from '@angular/common/http/testing';
    import { async, ComponentFixture, TestBed } from '@angular/core/testing';
    
    class AMock extends A {
      ngOnInit() {
        //privateState is now protected
        this.privateState = mockedState;
      }
    }
    describe('A', () => {
      let component: AMock;
      let fixture: ComponentFixture<AMock>;
    
      beforeEach(async(() => {
        TestBed.configureTestingModule({
          imports: [HttpClientTestingModule],
          declarations: [AMock]
        })
          .compileComponents().catch();
      }));
    
      beforeEach(() => {
        fixture = TestBed.createComponent(AMock);
        component = fixture.componentInstance;
      });
    
      it('testedFunction should set up public state correctly', () => {
        component.testedFunction();
    
        expect(component.publicState).toEqual(mockedState.something);
      });
    
    从'@angular/common/http/testing'导入{HttpClientTestingModule};
    从“@angular/core/testing”导入{async,ComponentFixture,TestBed};
    类AMock扩展了{
    恩戈尼尼特(){
    //私有国家现在受到保护
    this.privateState=mockedState;
    }
    }
    描述('A',()=>{
    let组件:AMock;
    let夹具:组件夹具;
    beforeach(异步(()=>{
    TestBed.configureTestingModule({
    导入:[HttpClientTestingModule],
    声明:[阿莫克]
    })
    .compileComponents().catch();
    }));
    在每个之前(()=>{
    fixture=TestBed.createComponent(AMock);
    组件=fixture.componentInstance;
    });
    它('testedFunction应该正确设置公共状态',()=>{
    testedFunction();
    expect(component.publicState).toEqual(mockedState.something);
    });
    
    运行
    ng test
    命令后,由于无法读取未定义的属性“testedFunction”,最后一点不起作用,返回错误


我不知道哪种方法是正确的测试方法。我知道我可以将
hiddenComplexFunction
公开,我的所有问题都会消失,而且我不喜欢因为测试而必须更改访问修饰符(从private改为protected,就像在模拟示例中一样,这对我来说似乎完全错误).

你的问题有很多,所以我将从我能很容易看到的东西开始

我们可以从您的核心组件代码开始。在testedFunction()中,调用this.hiddenComplexFunction()。您需要该函数的实例版本,因此需要将“this.”添加到其中。这非常合适,而且您也不想直接测试私有函数/私有属性

接下来,我猜你想要这个代码

this.state = x['whatever'];
设置您的私有状态,而不是状态

this.privateState = x['whatever'];
接下来,你不需要用你的AMock类来模拟A,测试装配会帮你做到这一点。尝试下面的方法作为开始。我这里没有的是状态代码。我真正做的就是去掉你的AMock,用实际的组件替换它,并构建一个测试状态(我可能会补充说,这个状态构建得很糟糕。哈!).我处理下面的HTTP数据,通过查看您的代码,我猜这些数据与您的状态有关

import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { A } from './zing.component';  // this should point to your component

// get rid of this, not needed
// class AMock extends A {
//   ngOnInit() {
//     //privateState is now protected
//     let privateState = mockedState;
//   }
// }

describe('A', () => {
  let component: A;  // changed from AMock to A
  let fixture: ComponentFixture<A>; // changed from AMock to A

  let mockedState = {something: 'yelp'}; // build your expected state here

  beforeEach(async(() => {
    TestBed.configureTestingModule({
      imports: [HttpClientTestingModule],
      declarations: [A] // changed from AMock to A
    })
      .compileComponents().catch();
  }));

  beforeEach(() => {
    fixture = TestBed.createComponent(A); // changed from AMock to A
    component = fixture.componentInstance;
  });

  it('testedFunction should set up public state correctly', () => {
    component.testedFunction();

    expect(component.publicState).toEqual(mockedState.something);
  });
});
在每次会议前—

backend = TestBed.get(HttpTestingController);
在你的IT声明中-

backend.expectOne(expectedURL).flush(mockedState);

backend.verify();

让我们知道这对你有多大帮助,如果它有用或者你有其他错误。

这是一个纯类,还是一个组件?你没有@component decorator,但正在尝试使用onInit,并尝试在测试中将其实例化为一个组件fixture。如果它是一个类,那将是一个不同于组件的答案。it是一个组件,我将添加decorator这似乎解决了我的大多数问题,有没有办法存根任何地址,而不必在expectedURL中指定一个地址?我想使用
backend.expectOne(()=>true).flush(mockedState);
不是测试请求的正确方法,您可以尝试使用-const backendRequest=backend.expectOne((请求:HttpRequest,在使用HttpClientTestingModule头设置第二个规范(我的站点)下)还有,对代码进行优化-从ngOnInit中删除功能。生命周期方法很难测试。将该代码添加到getData()中然后,您可以轻松地测试该方法中数据的检索,并能够模拟该方法来测试依赖于该方法的其他代码。
backend.expectOne(expectedURL).flush(mockedState);

backend.verify();