У меня есть класс ViewController, который представляет серию из двух всплывающих окон. Каждое всплывающее окно с двумя вариантами выбора отличается.
Popup1 - Choice1 -> Choice1Popup
Popup1 - Choice2 -> Choice2Popup
Я хочу, чтобы метод представлял Popup1 как общедоступный, но я хочу, чтобы другие методы, которые представляют Choice1Popup и Choice2Popup, были частными.
Если я решу, что мне нужно протестировать Choice1Popup и Choice2Popup, то мне, возможно, придется сделать их внутренними, а не частными, но вряд ли они когда-либо будут использоваться из любого другого места.
Я хочу написать модульный тест, который проверяет, когда при нажатии кнопки для Choice1 вызывается метод, представляющий Choice1Popup. Я использовал протокол с переменными типа метода, чтобы позволить Mock вводить версии Mock всплывающих окон. Я не чувствую себя на 100% комфортно в своем подходе, поэтому я хотел узнать, есть ли лучший способ.
Кроме того, я чувствую конфликт между внутренним и личным. Было бы неплохо иметь возможность тестировать мои закрытые методы, но я не хочу, чтобы их можно было вызывать из любого места, кроме модульного теста, и их внутреннее представление обнажает их.
Вот код и единичный тестовый модуль внизу:
// protocol to be used by both UserChoices class and UserChoicesMock for method injection
protocol UserChoicesPrivateUnitTesting {
static var choice1Method:(UIViewController) -> Void { get set }
static var choice2Method:(UIViewController) -> Void { get set }
}
// this popup that will be presented with a public method
public class ChoiceViewController:UIViewController {
@IBOutlet weak var titleLabel: UILabel!
@IBOutlet weak var subjectLabel: UILabel!
@IBOutlet weak var choice1Button: UIButton!
@IBOutlet weak var choice2Button: UIButton!
var choice1Action:(() -> Void)?
var choice2Action:(() -> Void)?
// ...
}
public class UserChoices: UIViewController, UserChoicesPrivateUnitTesting {
static var choice1Method: (UIViewController) -> Void = choice1
static var choice2Method: (UIViewController) -> Void = choice2
private static func choice1(onTopViewController: UIViewController) {
//present choice1Popup
}
private static func choice2(onTopViewController: UIViewController) {
//present choice2Popup
}
public static func presentChoiceViewController(onTopViewController: UIViewController, ChoiceViewController: ChoiceViewController = ChoiceViewController.instantiateFromAppStoryBoard(appStoryBoard: .MenuStoryboard)) {
let isCustomAnimated = true
// ChoiceViewController.transitioningDelegate = transitionDelegate
ChoiceViewController.choice1Action = { [weak onTopViewController]() in
guard let weakSelf = onTopViewController else {
return
}
weakSelf.dismiss(animated: false, completion: nil)
UserChoices.choice1Method(onTopViewController!)
}
ChoiceViewController.choice2Action = { [weak onTopViewController]() in
guard let weakSelf = onTopViewController else {
return
}
weakSelf.dismiss(animated: false, completion: nil)
UserChoices.choice2Method(onTopViewController!)
}
onTopViewController.present(ChoiceViewController, animated: isCustomAnimated, completion: nil)
}
}
import XCTest
@testable import ChoiceModule
public class UserChoicesMock:UserChoicesPrivateUnitTesting {
static public var choice1Method: (UIViewController) -> Void = choice1
static public var choice2Method: (UIViewController) -> Void = choice2
static var choice1MethodCalled = false
static var choice2MethodCalled = false
static func choice1(onTopViewController: UIViewController) {
choice1MethodCalled = true
}
static func choice2(onTopViewController: UIViewController) {
choice2MethodCalled = true
}
}
class UserChoicesTests: XCTestCase {
func testChoice1CallsPrivateChoice1Method() {
// This is an example of a functional test case.
let vc = UIViewController()
let choiceViewController = ChoiceViewController.instantiateFromAppStoryBoard(appStoryBoard: .MenuStoryboard)
UserChoices.choice1Method = UserChoicesMock.choice1Method
UserChoices.presentChoiceViewController(onTopViewController: vc, ChoiceViewController: choiceViewController)
choiceViewController.choice1Button.sendActions(for: .touchUpInside)
if UserChoicesMock.choice1MethodCalled == false {
XCTFail("choice1Method not called")
}
}
}