2016-07-31 35 views
0

Sorry, wenn es ein bisschen lang ist, aber ich wollte mich gut erklären.Test abgebrochen, wenn geändertes Modell mit Schnittstellen zu Klassen

Ich habe einen Test für einen API Anruf im Ausführen von meinem Dienst, um einen einfachen JSON zu erhalten. (Karma-jasmin/angular2)

dies ist der Anruf von meinem Service:

@Injectable() 
export class MyService { 

    constructor(private _myApiService:MyAPIService) { 
    } 

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

} 

das ist 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); 
    } 

Car-Schnittstelle ist:

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

die json Es sieht so aus (Teil eines Mocks):

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

-Test: Der Test ist für 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, also das funktioniert! Das Problem ist, wenn ich mein Modell aus dieser

geändert
interface: 

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

zu dieser Klasse:

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; 
} 

so jetzt der Fehler im bekommen ist:

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 })] 

Also das Problem ist ziemlich offensichtlich, aber wie repariere ich das, ich meine mit der aktuellen Änderung, was wäre ein geeigneter Weg, um diesen Test zu ändern?

durch ein Bündel für diejenigen, die zu diesem Zeitpunkt überlebt :)

Antwort

1

toEqualcarsExpectedResponse() Array-Elemente erwarten Instanzen von bestimmten Klasse (zum Beispiel Car) zu sein. Es tests object constructors und erwartet, dass sie eine nicht aufzählbare Eigenschaft constructor haben, die einen Konstruktor enthält.

Es kann ein echtes Beispiel sein:

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

Es kann eine Fälschung nicht-enumerable constructor Eigenschaft sein:

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

Es kann ein Objekt mit dem gewünschten Prototypkette aufgebaut sein:

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

Das letzte Fixture-Objekt ist wahrscheinlich das stabilste, weil es nicht dep end auf Jasmin interne Logik und hängt auch nicht von Konstruktor Logik.

+0

danke mann. aber was mache ich jetzt mit dem anderen Argument des Objekts? es erwartet nun auch eine funktion im objekt implementiert zu sein ... wie füge ich es hinzu? –

+0

@jackmiao Gibt es einen Grund, warum es definiert ist als 'displayFormat :() => string = function() {...}' Eigenschaft und nicht 'displayFormat() {...}' Methode? Der zweite wird am Objektprototyp definiert und wird beim Objektvergleich nicht berücksichtigt. – estus

+0

versuchte es jetzt, um die Methodensignatur zu ändern, und immer noch attay von leeren Objekten zu erhalten, um [MatcherEntityBulk ({}), ... ' –