2016-09-30 7 views
7

Проблема в том, что насмешка в TypScript может оказаться сложной, если объект достаточно сложный (хорошо на любом строго типизированном языке). Обычно вы издеваетесь над некоторыми дополнительными материалами, чтобы сделать компиляцию кода и, например, в C#, вы можете использовать AutoFixture или подобное. С другой стороны, Javascript - это динамический язык, и есть возможность высмеять только часть объекта, которая необходима для запуска теста.Издевательствование в модульных тестах TypScript

Так что в тесте Unitcript я могу объявить свою зависимость, используя тип any и, таким образом, легко издеваться над ней. Вы видите какие-то недостатки такого подхода?

let userServiceMock: MyApp.Services.UserService = { 
    // lots of thing to mock 
} 

против

let userServiceMock: any = { 
    user: { 
     setting: { 
      showAvatar: true 
     } 
    } 
} 

ответ

10

Моего опыта работы с модульными тестами в машинописи определенно показывает, что стоит держать все фиктивный объект набранным. Когда вы оставляете свои издевательства с типом any, это становится проблематичным во время переименования. IDE не будет правильно обнаруживать, какие изменения должны быть изменены в параметрах user или settings. Конечно, рукописный макет вручную с полным интерфейсом действительно трудоемкий.

К счастью, есть два инструмента для машинописи, что позволяет создавать безопасные типа фиктивных объектов: ts-mockito (вдохновленного Java mockito) и typemoq (вдохновленной C# Moq).

+2

я написал статью, сравнивая две библиотеки: https://medium.com/@michal.m.stocki/when-it-comes-to-mocking-in-typescript-be8531d39327 – Terite

+0

Я написал мой собственный инструмент, который справляется с этой же проблемой, и мне хотелось бы получить от него некоторые отзывы: https://medium.com/default-to-open/unit-testing-with-angular-and-ineeda-76746a0c8f58 – phenomnomnominal

1

Как указано в @Terite any тип на mocks является плохим выбором, так как между mock и его фактическим типом/реализацией не будет никакой связи. Таким образом, улучшенное решение может быть литье частично высмеивал объект издевается типа:

export interface UserService { 
    getUser: (id: number) => User; 
    saveUser: (user: User) => void; 
    // ... number of other methods/fields 
} 

.......

let userServiceMock: UserService = <UserService> { 
    saveUser(user: User) { console.log("save user"); } 
} 
spyOn(userServiceMock, 'getUser').andReturn(new User()); 
expect(userServiceMock.getUser).toHaveBeenCalledWith(expectedUserId); 

Также стоит отметить, что Машинопись не допустит, чтобы бросить любой объект, имеет дополнительные члены (надмножество или производный тип). Означает, что ваш частичный макет на самом деле имеет базовый тип для UserService и может быть безопасно отлит. например

// Error: Neither type '...' nor 'UserService' is assignable to the other. 
let userServiceMock: UserService = <UserService> { 
    saveUser(user: User) { console.log("save user"); }, 
    extraFunc:() => { } // not available in UserService 
} 
+0

Почему, так важно, чтобы вы частично издевались над предметами? Плохая идея иметь публичные поля и общедоступные методы в одной службе. Лучше было бы определить метод 'setAvatarVisibility (visible: boolean)' и оставить поле 'user' частным. Тогда вы избежите ручного шпионажа. Обратите внимание, что в 'spyOn (userServiceMock, 'saveUser');' имя строки метода не будет автоматически реконфигурироваться с помощью IDE. – Terite

+0

Еще одним лучшим решением было бы оставить объект 'user' вне службы вообще. Код легче тестировать, если мы сохраняем услуги без гражданства. Что вы думаете о том, что пользователь UserService принимает пользователя к его методу: 'saveUser (user: User): void;'? – Terite

+0

Я использовал этот код только как пример, может быть, не самый лучший, но это не то, что я пытался издеваться. Я просто ищу общее решение. И да, ваши примеры лучше, конечно, спасибо за совет. –

Смежные вопросы