I have been using OCUnit for unit testing in a project. I've managed to do all the setup required for OCUnit in Xcode 4.2 & successfully build my test cases.
How can I control the order (priority) for a test case? I see that test cases are built in alphabetic order of their name, i.e. if I have test method testA, testB, testC, they'll be executed in that same order.
What I need is for "testC" in the above example to be executed before "testB", as my method has some setup for variables & preferences for "testB", as well as core data entry, included in "testC".
Either your make your test cases self-contained, so that they can run on their own without pre-conditions, or you name your test methods accordingly as you mentioned.
test0First, test1Second
I would recommend to make them self-contained. It's a little overhead, but you can implement reusable methods in your test case (that don't start with test) to make your life easier.
If you want a framework with more features check out GHUnit
Related
I wrote my own ORM framework (something along the lines of CoreData or Realm), and also wrote quite a few tests in Xcode for it.
Now I want to introduce an additional encoding format used for storing data on disk, but I also want to keep supporting the original encoding format.
Is there a good strategy to run my all my existing -test* methods for both encoding formats without duplicating the existing test code?
The easiest way I have found is to just create a new test target and add all the same test classes to it. If you want them run in one go, create a target that has both of these test targets as dependencies (or just runs them manually).
How you parametrize for your different targets is up to you, we've successfully used two implementations of a category that has the definition that varies.
I once asked a question related to XCTests. And in one of the answers I was told that it is a common practice to use a separate test target (other than the main app) when running unit tests (at least, in iOS development). I tried to find some sources about it, but I couldn't
I understand, that it is probably a best practice, so I would really like to understand it. Could someone explain to me why is it important, what benefits do I get from it and how should I go about doing it? Links to some articles explaining the issue will be much appreciated.
P.S. I understand that I need special environment for tests (fake in-memory database, mocked networking layer, etc.), but up until now I managed to achieve it without a separate test host. But I believe that there might be a better way.
To answer your points:
Why is using a separate test target important?
Separation of concerns. A unit test target does not have the same kind of structure as a regular app target - it contains a test bundle, which references the app target under test, as well as the test classes and any helper classes required. It is not a duplicate of the app target with test code added to it - in fact it should not even contain the code under test. This means that you don't have to make any special effort to keep the test target in sync with the main app target - the fact that the test bundle loads the main app handles all that for you. (You made a comment on Richard Ross's answer to your previous q suggesting you've run into the difficulties duplication causes already).
How should I go about doing this? (checked on Xcode 7).
Assuming you are wanting to add a target to an existing project that doesn't have any tests, select the main project, and then click on the '+' beneath the list of targets in the project. You can also use the File->New->Target menu option.
You'll see a menu asking you to choose a template for your new target. Select 'Test' and within test select 'iOS Unit Testing Bundle'.
Check the fields in the next screen - they should be correct by default - but you might want to double check the 'Target to be Tested' field value is correct if you have a lot of targets in the project/workspace. Click 'OK' and you should have a functioning unit test bundle, with an example test that you should be able to run using Apple-U or Product->Test You'll still need to #import the app classes if you're using ObjC.
If you are creating a new project, all you need to do is tick the 'Include Unit Test' box when creating the project - no other steps are required.
Apple Docs (with links to relevant WWDC presentations)
Tutorials. Most of the tutorials around are a bit out of date. But not that much has changed, so just look at the docs and figure it out. The two below might be useful, otherwise just google. From a quick glance, most of them seem to assume that the project had unit tests set up at the beginning
http://www.raywenderlich.com/22590/beginning-automated-testing-with-xcode-part-12 (2012/iOS 6, but the process is still broadly the same. Also deals with Jenkins, Git and running tests from the CLI).
Unit testing in OSX - most recent post - not iOS, I know, but more up to date than most of the iOS tutorials (Oct 2015), and gives step by step instructions (including setting the unit test target in the build schemes, which probably won't be necessary in your case). Probably worth a look anyway.
So, i have already existing project at my hands and i’m trying to create some UI tests by using this new fancy UI Testing Bundle provided by apple. The problem is that test target doesn't have access to any external framework (and i need to do some setup with one of them). Adding framework in build phases and coping framework search path from main target doesn't do anything.
After day of browsing i found out only one thing, that ”makes things kinda different”. By setting up Bundle Loader and Test Host to $(BUILT_PRODUCTS_DIR)/App.app/App , i still couldn't import external frameworks to test.m, but i could import classes that do that for them self. And it all would be fine and dandy unless it didn't break some stuff. By setting Bundle and Host now my UI test is unable to execute launch method:
[[[XCUIApplication alloc] init] launch];
It crashes with error: Assertion Failure: UI Testing Failure - App state is still not terminated.
In the end i could remove launch method from setup and trigger every single test manually, so it restarts application every time before executing, but this solution seems so wrong (especially for some bigger projects). Does anyone know proper way to handle this problem?
What I've done for this is add an environment variable to XCUIApplication to specify UI tests are being run. I then have a pre-processor check for #DEBUG in a main part of the application, and then check if the test environment variable has been set; if it has, do the necessary steps for the UI tests.
Essentially, this will allow you to configure your app to how you need it for the UI tests to run. It also means the pre-processor check will strip out that setup code entirely for the release build.
I am trying to implement XCTest as I have a bug in an iOS App which I don't seem to figure out so want to start building up get cases.
The App however, when loaded, will automatically connect to a server to update data. For the tests however, I would like this not to happen, as I need to clear the CoreData database and populate for each test.
Is there a way to know when e.g. building (on the target) if tests are going to be ran? Ie so I can use a flag to to leave out certain actions when testing?
Or should I just duplicate my normal target specifically for tests, and put in a flag that way?
(e.g. #if TESTING instead of #if DEBUG)
Not a direct answer to your question, but it might be a solution to your problem.
You could mock your class that does the server connection (ie fake the server connection).
You can do this by using OCMock that you can find here or OCMockito that can be found here.
Currently, I find OCMock easier to implement with XCTest than OCMockito. However, there might be some issues with OCMock as well, but those can be ironed out be looking at this site.
I've found plenty of people using Xcode 3 to do this, but it no longer seems to work in Xcode 4. Or, it works partially…
I've added a preprocessor macro "TEST_TARGET" for Debug and Release under my Test target, and if I use #ifdef TEST_TARGET in the actual unit tests, that works as expected.
However, I really want to log some extra information from a source file that's just part of the main app when it's being run under unit tests (i.e. just a standard source file, not a unit test file). That source file doesn't appear to "see" the define. I've stepped through with the debugger, and the code within #ifdef is never executed.
Is there a way to tell my app is being run under a unit test target?
Here's how you can do it: you can test for something that's loaded when the tests are loaded, but not when they aren't.
For instance:
if (NSClassFromString(#"SenTest")) {
NSLog(#"Extra info when running tests");
}
You could also add categories to your classes that are only present in the test target, which might also be helpful.