2016-07-31 2 views
0

Извините, если он немного длинный, но я хотел хорошо объяснить себя.тест сломался, когда была изменена модель с интерфейсами к классам

У меня есть тест на вызов api, выполняющий мою службу, чтобы получить простой json. (Карма-жасмин/angular2)

это вызов из службы:

@Injectable() 
export class MyService { 

    constructor(private _myApiService:MyAPIService) { 
    } 

    public getCarsData():Observable<Car[]> { 
    return this._myApiService.getCurrentCarData().map(res => res.carList); 
    } 

} 

это getCurrentCarData():

export interface CarsListResponse extends ServerResponse { 
    carList: Cars[]; 
} 

public getCurrentCarData(): Observable<CarsListResponse> { 
    let apiURL = 'my/api/url' 
    return this.http.get(apiURL), 
     (ret, retJson) => ret.status === 200 ? {carList: retJson.cars.map(element => new Car(element.year, element.make))} : undefined); 
    } 

интерфейс автомобиля является:

export interface Car { 
    make:string; 
    year:number; 
} 

JSON Im получение выглядит так (часть макета):

status: 200, 
     headers: new Headers(HEADERS), 
     body: { 
      cars: [ 
      { 
       "make": "Mercedes", 
       "year": 2016 
      }, 
      { 
       "make": "Audi", 
       "year": 2017 
      }, 
      { 
       "make": "BMW", 
       "year": 2015 
      } 
      ] 
     } 

испытания: испытание для getCurrentCarData():

let carsResponse =() => { 
    return { cars: [ 
      { 
       "make": "Mercedes", 
       "year": 2016 
      }, 
      { 
       "make": "Audi", 
       "year": 2017 
      }, 
      { 
       "make": "BMW", 
       "year": 2015 
      } 
      ]} 
}; 

let carsExpectedResponse =() => { 
    return [ 
      { 
       "make": "Mercedes", 
       "year": 2016 
      }, 
      { 
       "make": "Audi", 
       "year": 2017 
      }, 
      { 
       "make": "BMW", 
       "year": 2015 
      } 
      ] 
}; 
describe('GET Car Data',() => { 

    it('should handle respond', inject([XHRBackend, api.MyApiService], (mock, myApiService) => { 

     let c:Connection = null; 
     mock.connections.subscribe((connection) => { 
     connection.mock(new Response(new ResponseOptions({ 
      status: 200, 
      headers: jsoHeaders(), 
      body: carsResponse() 
     }))); 
     c = connection; 
     }); 

     myApiService.getCurrentCarData().subscribe(
     res => { 
      expect(c.request.url).toEqual(`my/api/url`); 
      expect(res.carList).toEqual(carsExpectedResponse()); 
     }, 
     error => { 
      expect(false).toBeTruthy(); 
     } 
    ); 
    })); 

    }); 

Ok, так что это работает! Проблема заключается в том, когда я изменил мою модель из этого

interface: 

    export interface Car { 
     make:string; 
     year:number; 
    } 

к этому классу:

export class Car implements GenType { 
      make:string; 
      year:number; 

    constructor(make:string, year:number) { 
    this.make = make; 
    this.year = year; 
    } 

    displayFormat:() => string = function() { 
    return 'someStr' 
    } 
} 

export interface GenType { 
    displayFormat:() => string; 
} 

так что теперь им ошибки получают:

Expected 
      [MatcherEntityBulk({ displayFormat: Function, make: 'Mercedes', year: 2016 }), 
      MatcherEntityBulk({ displayFormat: Function, make: 'Audi', year: 2017 }), 
      MatcherEntityBulk({ displayFormat: Function, make: 'BMW', year: 2015 })] 
to equal 
      [Object({ displayFormat: Function, make: 'Mercedes', year: 2016 }), 
      Object({ displayFormat: Function, make: 'Audi', year: 2017 }), 
      Object({ displayFormat: Function, make: 'BMW', year: 2015 })] 

Таким образом, проблема довольно очевидно, но как я исправить это, я имею в виду с текущим изменением, что было бы правильным способом изменить этот тест?

спасибо кучи для тех, которые сохранились до этого момента :)

ответ

1

toEqual ожидает carsExpectedResponse() элементов массива, чтобы быть экземплярами определенного класса (например, Car). Он tests object constructors и ожидает, что у них будет неперечислимое свойство constructor, которое содержит конструктор.

Это может быть реальным примером:

let carsExpectedResponse =() => [ 
    new Car(...), 
    ... 
]; 

Это может быть поддельным несчетное constructor свойством:

let carsExpectedResponse =() => [ 
    { 
    "make": "Mercedes", 
    "year": 2016 
    }, 
    ... 
].map(obj => Object.defineProperty(obj, 'constructor', { value: Car })); 

Это может быть объектом, построенный с желаемой цепью прототипов:

let carsExpectedResponse =() => [ 
    { 
    "make": "Mercedes", 
    "year": 2016 
    }, 
    ... 
].map(obj => Object.assign(Object.create(Car.prototype), obj)); 

Последний объект крепления, вероятно, самый твердый, потому что он не отпечатывается заканчивается внутренней логикой Jasmine и не зависит также от логики конструктора.

+0

спасибо, человек. но что мне теперь делать с другим аргументом объекта? потому что он ожидает, что теперь функция будет реализована в объекте ... как ее добавить? –

+0

@jackmiao Есть ли причина, по которой он определяется как 'displayFormat :() => string = function() {...}', а не 'displayFormat() {...}' method? Второй будет определен на прототипе объекта и не будет учитываться при сравнении объектов. – estus

+0

попробовал это, чтобы изменить сигнатуру метода и все равно получить пустые объекты 'to equal [MatcherEntityBulk ({}), ...' –