2012-11-27 17 views
6

Ich habe einen Dienst, der mehrere meiner anderen Dienste als Abhängigkeit nimmt. Wie kann ich es für einen Komponententest verhöhnen?Mocking mein eigener Dienst in einem Komponententest

myApp.factory('serviceToTest', 
      ['serviceDependency', 
    function(serviceDependency) { 
     return function(args) { 
      return cond(args) ? serviceDependency() : somethingElse(); 
     }; 
    } 
]); 

Im obigen Beispiel möchte ich serviceDependency so kann ich, dass es genannt wurde überprüfen verspotten. Wie kann ich das machen?

konnte ich nur folgend im Test:

describe("Services", function() { 
    describe('serviceToTest', function() { 

     myApp.factory('serviceDependency', function() { 
      var timesCalled = 0; 
      return function() { 
       return timesCalled++; 
      } 
     }); 

     it('should do foo', inject(function(serviceToTest, serviceDependency) { 
      serviceToTest(["foo", "bar", "baz"]); 
      expect(serviceDependency()).to.equal(1); 
     }); 
    }); 
}); 

Dies funktioniert für den Test in Ordnung, die den Schein braucht, aber es wirkt mich dann den Zustand aller anderen Tests, die folgen, was offensichtlich ein Problem.

+0

In Ihrem Test wie erhalten Sie die Instanz von ServiceToTest? –

+0

@RoyTruelove OP aktualisiert –

Antwort

11

Wenn ich Sie richtig verstehe, möchten Sie einen Dienst testen, der von einem anderen Dienst abhängt, und eine Abhängigkeit für jeden Test vortäuschen. Wenn ja, lassen Sie uns sagen, dass wir eine car haben, die eine Abhängigkeit von einem engine hat:

var app = angular.module('plunker', []) 
    .factory('car', function(engine) { 
    return { 
     drive : function() { 
     return 'Driving: ' + engine.speed(); 
     } 
    } 
    }) 
    .value('engine', { 
    speed : function() { 
     return 'fast'; 
    } 
    }); 

Dann möchten Sie ein Auto testen und einen Motor verspotten. Es gibt 2 Möglichkeiten, dies zu tun: entweder durch ein neues Modul zu definieren, in dem wir einen Motor neu definieren könnten:

describe('Testing a car', function() { 
    var testEngine; 

    beforeEach(function(){ 
    testEngine = {}; 
    angular.module('test', ['plunker']).value('engine', testEngine); 
    module('test'); 
    }); 

    it('should drive slow with a slow engine', inject(function(car) { 
    testEngine.speed = function() { 
     return 'slow'; 
    }; 
    expect(car.drive()).toEqual('Driving: slow'); 
    })); 
}); 

Eine Arbeits zupft hier: http://plnkr.co/edit/ueXIzk?p=preview

Etwas einfachere Alternative, die Weiterleitung auf dynamische Art von JavaScript :

describe('Testing a car', function() { 
    var testEngine; 

    beforeEach(module('plunker')); 
    beforeEach(inject(function(engine){ 
    testEngine = engine; 
    })); 

    it('should drive slow with a slow engine', inject(function(car) { 
    testEngine.speed = function() { 
     return 'slow'; 
    }; 
    expect(car.drive()).toEqual('Driving: slow'); 
    })); 
}); 

http://plnkr.co/edit/tlHnsJ?p=preview

Noch eine weitere Alternative eines Jasmins Spion verwenden:

describe('Testing a car', function() { 
    var testEngine; 

    beforeEach(module('plunker')); 
    beforeEach(inject(function(engine){ 
    testEngine = engine; 
    })); 

    it('should drive slow with a slow engine', inject(function(car) { 
    spyOn(testEngine, 'speed').andReturn('slow'); 
    expect(car.drive()).toEqual('Driving: slow'); 
    })); 
}); 

http://plnkr.co/edit/K4jczI?p=preview

+0

können Sie bitte erklären, wie es geht, wenn ich überhaupt nicht 'Engine' Abhängigkeit laden kann. In diesem Fall kann ich nicht testEngine = engine; Teil. –

+0

@KamalReddy 2 Jahre zu spät, aber für die Nachwelt: Verwenden Sie einfach die erste Lösung oben. Wenn Sie ein ganz neues 'testEngine' -Objekt definieren, das die Definition der ursprünglichen Abhängigkeit überschreibt, ist es egal, ob Sie 'engine' laden können. –

7

ich das gleiche Problem mit versuchen, einen Mock-Service in einen anderen Provider zu injizieren.

Dieser Beitrag von Pete Speck Darwin hat mich auf dem richtigen Weg: https://groups.google.com/d/msg/angular/TvBknXnjRyQ/xtCDkJyqp6MJ

Hier ist ein Beispiel-Anwendung:

angular.module('MyApplication', []) 
    .service('MyServiceDependency', [function(){ 
     // Behaviour here. 
    }]) 
    .factory('MyFactory', ['MyServiceDependency', function(MyServiceDependency){ 
     // Behaviour here. 
    }]); 

Wir wollen MyServiceDependency verspotten das Verhalten von MyFactory so testen wir schreiben unsere Tests wie folgt:

describe(function(){ 

    var MyFactory; 

    beforeEach(function(){ 
     // 1. Include your application module for testing. 
     angular.mock.module('MyApplication'); 

     // 2. Define a new module. 
     // 3. Define a provider with the same name as the one you want to mock (in our case we want to mock 'MyServiceDependency'. 
     angular.module('MyAppMock', []) 
      .service('MyServiceDependency', function(){ 
       // Define you mock behaviour here. 
      }); 

     // 4. Include your new mock module - this will override the providers from your original module. 
     angular.mock.module('MyAppMock'); 

     // 5. Get an instance of the provider you want to test. 
     inject(function($injector){ 
      // `MyFactory` will receive the mocked version of `MyServiceDependency`. 
      MyFactory = $injector.get('MyFactory'); 
     }); 
    }); 

    it('MyFactory does something special', function(){ 
     MyFactory(); // Test your provider. 
    }); 

}); 
+1

Schön - ich bezweifle, dass ich das alleine herausgefunden hätte. IMHO ist dies der flexibelste Ansatz, da Sie jetzt eine Reihe von benutzerdefinierten Mocks ** außerhalb der Unit-Tests definieren können. Dann können Sie in Komponententests auf die gleichen Mocks verweisen wie beim Einrichten einer laufenden Umgebung, in der externe Abhängigkeiten (z. B. Aufrufe von $ http) deaktiviert sind. – user1821052

Verwandte Themen