1

I am trying to test a class I have written. I have added a new test target and in there I have imported the target of the class I am trying to test. My code looks like this:

import XCTest
import TargetContainingClass

class Tests: XCTestCase
{
   var myClass = MyClass()

   // tests

}

However, I get the error:

'MyClass' is not constructible with '()'

MyClass does not contain an init() method so does not need to be constructed with anything. I therefore don't understand the error I am getting.

Any help here would be greatly appreciated.

Cheers

gcjensen
  • 11
  • 2
  • 1
    What is the definition of your MyClass? – AlBlue Aug 02 '14 at 16:52
  • It just has a bunch of functions. No instance variables or anything. – gcjensen Aug 02 '14 at 22:11
  • I've just tested this in beta 4, with a test case, exactly as you've described, and it worked fine, no compile errors. My MyClass was defined as `class MyClass { func testFunc() { println("This is testFunc") } }`. Either we need to see your code to figure out what's going on, or you're using an old beta. – Matt Gibson Aug 03 '14 at 07:36
  • Ah! Looks like it might be related to access control. See https://devforums.apple.com/message/1013522#1013522 (Though that doesn't explain why it works for me...) Try manually adding a default constructor: just `init() {}` looks like it should work to make the initialiser public. – Matt Gibson Aug 03 '14 at 08:26
  • The suggestions in the thread you linked to are that the `init()` needs to be made public. This solves the issue I posted about, but gives me new errors, as I've mentioned in the comments on the answer below. – gcjensen Aug 03 '14 at 10:04

2 Answers2

0

You need to provide an implementation of init() as:

class MyClass {
  init () {}
}

The Swift documentation states:

“Swift provides a default initializer for any structure or base class that provides 
 default values for all of its properties and does not provide at least one initializer
 itself. The default initializer simply creates a new instance with all of 
 its properties set to their default values.”  
    Apple Inc. “The Swift Programming Language.”

But the above is apparently not true; in action:

  1> class MyClass1 {}
  2> MyClass1()
/var/folders/.../expr.DO8uJ4.swift:2:1: error: 'MyClass1' is not constructible with '()'
MyClass1()
^
  2> class MyClass { 
  3.     init () {} 
  4. }    
  5> MyClass()
$R0: __lldb_expr_3.MyClass = {}
GoZoner
  • 67,920
  • 20
  • 95
  • 145
  • Hmm yes I didn't think `init() { }` was needed if nothing was being initialised? Adding `init() { }` gets rid of those errors but gives me `Apple Mach-O Linker (id) Error`. I know without seeing everything it's hard to say, but any initial thoughts? – gcjensen Aug 02 '14 at 23:08
  • 1
    What Xcode6 beta are you using? I just checked in Beta4 and `init()` is not needed; and my trivial test target links and runs. – GoZoner Aug 02 '14 at 23:39
  • Aha. That only happens in the repl, and also potentially in test cases as in the OP's case, because of [a problem introduced with the access controls](https://devforums.apple.com/message/1013522#1013522) that makes a default init() inaccessible. – Matt Gibson Aug 03 '14 at 08:29
  • I'm using Beta4. If `init()` isn't needed, what could the source of my error be then? – gcjensen Aug 03 '14 at 09:58
  • Yup, I was wrong. The problem does exist in beta 4. I'll see if I can reproduce your linker error in a minute. – Matt Gibson Aug 03 '14 at 16:41
  • Yes, there is a bug in the REPL (reported) that fails to correctly namespace classes (and structs) and fails to tie them together. If you paste in the entire content it works; and if you put the class definition on the same line as the use case, it works as well. Welcome to Swift! Type :help for assistance. 1> class MyClass{}; MyClass() $R0: __lldb_expr_1.MyClass = {} – AlBlue Aug 04 '14 at 08:26
  • @gcjensen Sorry, was pulled away. The only way I've found of getting it to work was to expose both the class and its init method as public. i.e. `public class MyClass { ... public init() {} ... }`. This article on Medium looks like a good exploration of the current state of affairs, and offers another workaround, that of adding the class under test as a compile target of the test project, so the methods don't have to be fully public. – Matt Gibson Aug 04 '14 at 10:20
  • Ooop: The link would help, wouldn't it? https://medium.com/swift-programming/swift-testing-privates-or-rather-internals-9a3ac5a8a501 – Matt Gibson Aug 04 '14 at 14:20
  • @MattGibson No problem! Exposing both the class and the init method as public gets rid of my initial error but gives me the `Apple Mach-O Linker (id) Error`'s I previously mentioned. Any thoughts on these? – gcjensen Aug 05 '14 at 10:56
  • @AlBlue So are you saying that would be the cause of my `Apple Mach-O Linker (id) Error`s? If one of my classes is a test class neither of those solutions would work though, would they? – gcjensen Aug 05 '14 at 10:58
  • @gcjensen Nope, I can't see them here. I can successfully run a test call of a (trivial) function with the class and initialiser public (in beta 4.) Have you re-tried with beta 5? I've not tested this case in 5 yet. – Matt Gibson Aug 05 '14 at 11:19
  • @MattGibson I've not been able to download beta 5 yet. I'll try it with that later and see what happens. – gcjensen Aug 05 '14 at 11:52
  • @MattGibson I'm still getting the same `Apple Mach-O Linker (id) Error` in Beta 5. – gcjensen Aug 05 '14 at 21:09
0

I solved my issue firstly by providing an implementation of init() {} as suggested by @GoZoner, then to get rid of the Apple Mach-O Linker (id) Error I had to add the class I wanted to test as a Compile Source in the build phases.

gcjensen
  • 11
  • 2