Search code examples
iosswiftxcodexctestibdesignable

IBDesignable Errors When Adding to Tests Target


I have a simple UIButton subclass that implements IBDesignable with an IBInspectable var:

@IBDesignable class Button: UIButton {
    @IBInspectable var borderColor: UIColor = UIColor.whiteColor() {
        didSet { layer.borderColor = borderColor.CGColor }
    }
}

I am not using this within a framework and it is working in Interface Builder as intended, however, once I add this subclass to my Tests target, it stops rendering live and I get the following errors:

Main.storyboard: error: IB Designables: Failed to update auto layout status: dlopen(TestTests.xctest, 1): Library not loaded: @rpath/XCTest.framework/XCTest
Referenced from: TestTests.xctest
Reason: image not found

Main.storyboard: error: IB Designables: Failed to render instance of Button: dlopen(TestTests.xctest, 1): Library not loaded: @rpath/XCTest.framework/XCTest
Referenced from: TestTests.xctest
Reason: image not found

If I remove IBDesignable and the IBInspectable vars, the errors go away - unfortunately so does the live rendering in Interface Builder.

How do I test against an IBDesignable class without these errors?


Solution

  • At first, I thought this was a kind of bug in Xcode. Following is the workaround I found:

    STEP 1

    Mark your class and properties as public.

    @IBDesignable public class Button: UIButton {
        @IBInspectable public var borderColor: UIColor = UIColor.whiteColor() {
            didSet { layer.borderColor = borderColor.CGColor }
        }
    
        @IBInspectable public var borderWidth:CGFloat = 0.0 {
            didSet { layer.borderWidth = borderWidth }
        }
    }
    

    STEP 2

    Import your application module from your "Tests" module.

    For example, assuming that your application is named MyGreatApp, in your MyGreatAppTests/MyGreatAppTests.swift:

    import UIKit
    import XCTest
    import MyGreatApp
    
    class MyGreatAppTests: XCTestCase {
    
        func testExample() {
            let btn = Button()
            btn.borderColor = UIColor.redColor()
            XCTAssertEqual(UIColor(CGColor:btn.layer.borderColor), UIColor.redColor(), "borderColor")
        }
    }
    

    You don't need to add 'Button.swift' to your "Tests" target.

    STEP 3 (for Swift)

    In your storyboard explicitly select the module MyGreatApp for any custom classes instead of letting Xcode use the current module.

    Interface Builder select main target module