Writing a block test to extend a class in Swift

I am trying to write unit test to extend a class in Swift. The class extension itself will represent UIAlert with the specified header and message as such:

 extension UIViewController { func presentAlert(title: String, message : String) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert) alertController.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil)) UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController, animated: true, completion: nil) } } 

I created a file for my unit test containing the following code:

 import XCTest class AlertTest: XCTestCase { func testAlert() { let alert = presentAlert("Presented Alert", "This is an Alert!") } } 

However, I keep getting the error "Use of unresolved identifier 'presentAlert'" . I tried adding public to my extension after consulting this SO stream :

public func presentAlert(title: String, message : String)

but still no luck. Does anyone have an understanding?

EDIT

Based on @hkgumbs answer, this is my current code to extend my warning:

 import Foundation protocol Presentable {} extension UIViewController { public func presentAlert(title: String, message : String) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert) alertController.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil)) UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController, animated: true, completion: nil) } } 

In the view controller, where I want to show a warning, this would still be the right way to trigger my warning, right?

 self.presentAlert("Invalid URL", message: "Please try again") 

Secondly, based on your comment, this is what I understand by invoking Presentable in a dummy value, but it is incorrect because SomethingPresentable does not have a PresentAlert member. Where am I mistaken in my understanding?

 func testAlert() { let app = XCUIApplication() struct SomethingPresentable: Presentable {} SomethingPresentable.presentAlert("Presented Alert", message: "This is an Alert!") XCTAssert(app.alerts["Presented Alert"].exists) app.alerts["Presented Alert"].tap(); } 

EDIT 2 @hkgumbs based on your last comment, this is what I have for the extension:

 import Foundation protocol Presentable {} extension Presentable { func presentAlert(title: String, message : String) { let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert) alertController.addAction(UIAlertAction(title: "Close", style: UIAlertActionStyle.Default, handler: nil)) UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alertController, animated: true, completion: nil) } } 

And this is how I try to call it from my ViewController:

 Presentable.presentAlert("Invalid URL", message: "Please try again") 

However, I get the error "Using a member of the PresentAlert instance for type Self ; did you mean to use a variable of type Self instead?"

Then, I guess the test will look like this?

 func testAlert() { let app = XCUIApplication() struct SomethingPresentable: Presentable {} SomethingPresentable.presentAlert("Presented Alert", message: "This is an Alert!") XCTAssert(app.alerts["Presented Alert"].exists) app.alerts["Presented Alert"].tap(); } 
+5
source share
1 answer

As @dan pointed out , you need to call it from an UIViewController instance. Usually you do not want to create infrastructure objects in your tests if you can avoid this, so there are some options here to avoid this:

  • Make presentAlert static so you can just UIViewController.presentAlert
  • Make presentAlert free feature (do not put it in an extension)
  • Extend the protocol instead - I think this is the cleanest option

 protocol Presentable {} extension Presentable { func presentAlert(title: String, message : String) { /* ... */ } } 

Then, when you need it, you can extension UIViewController: Presentable {} . And in your tests, you can just use a dummy class. An additional advantage of this approach is that you can reuse this function on any type, if necessary, without exposing it globally when you do not.

Adding

When we extend the protocol, we say: "everything that implements this protocol will receive this method for free." The trick here is that this protocol is empty and therefore very easy to "implement."

 extension YourViewController: Presentable {} 
+4
source

All Articles