Дразнить со Свифтом
Рассмотрим следующий класс с именем SomeClass, написанный на Swift:
@objc class SomeClass: NSObject
{
var shouldCallBar = false
func foo()
{
if (shouldCallBar == true)
{
bar()
}
}
func bar()
{
}
}
Для тестирования описанного выше метода класса foo() (и подобных сценариев, в основном написанных на Objective-C), я использовал OCMock, например:
- (void) testFooBarShouldBeCalledWhenShouldCallBarIsTrue
{
SomeClass * someClass = [SomeClass new];
// Create mocks.
id mockSomeClass = OCMPartialMock(someClass);
// Expect.
[[mockSomeClass expect] bar];
// Stub.
someClass.shouldCallBar = YES;
// Run code under test.
[someClass foo];
// Verify.
[mockSomeClass verify];
// Stop mocking.
[mockSomeClass stopMocking];
}
Но приведенный выше тест завершается неудачно с кодом Swift, поскольку OCMock не будет хорошо работать со Swift.
Итак, я рассматриваю что-то вроде целиком в Swift:
class SomeClassTests: XCTestCase
{
class MockSomeClass: SomeClass
{
var isBarCalled = false
override func bar()
{
isBarCalled = true
}
}
func testBarShouldBeCalledWhenTrue()
{
let someClass = MockSomeClass()
someClass.shouldCallBar = true
someClass.foo()
XCTAssertTrue(someClass.isBarCalled == true)
}
}
Обратите внимание, что здесь я создаю подкласс для тестируемого исходного класса и переопределяю bar (). Я совсем не касаюсь реализации foo().
Но недостатком является то, что я использую экземпляр MockSomeClass для тестирования foo() SomeClass. Это то, что мне не нравится и не рекомендуется.
Есть ли лучшее решение проблемы выше?
Заметки:
- Я не говорю о внедрении зависимости здесь. Внедрение зависимостей - это совершенно другой подход.
- Я сталкиваюсь с такими проблемами при тестировании кода пользовательского интерфейса в UIViewController.
- Я думал о программировании на основе протокола, но не смог найти решение проблемы выше.
1 ответ
Итак, вы хотите проверить этот метод (foo
) вызывает или не вызывает другой метод (bar
). foo
метод является тестируемым, а bar
В широком смысле метод является зависимым компонентом.
Если вызов bar
Имеет длительные побочные эффекты, вы можете избежать тестирования, что побочный эффект есть / не присутствует, возможно, запросив свойство или подобное. В этом случае вам не нужно издеваться или подобное.
Если побочных эффектов нет, вы должны заменить зависимость. Для этого вам нужен шов, в который вы помещаете код, который может сообщить тесту, был ли вызван метод или нет. Для этого я вижу только два варианта, которые Джон уже обсуждал в вопросе, на который вы ссылаетесь.
Вы либо помещаете два метода в отдельные классы, и в этом случае границей класса является шов. Используя протокол или просто неофициальное соглашение, вы можете полностью заменить класс, который реализует bar
, Инъекция зависимости здесь пригодится.
Если два метода должны оставаться в одном и том же классе, то вы должны использовать границу подкласса в качестве шва, т.е. вы используете тот факт, что вы можете переопределить методы и реализовать специфичный для теста подкласс. Это проще всего, когда вы можете использовать макет фреймворка. Если это не вариант, вы должны написать код самостоятельно, очень похоже на то, что вы описываете в своем вопросе.