I am writing tests for my iPhone app using OCUnit.
Is there any way to debug the unit tests and have a break point to see what the heck is happening?
It's ridiculously hard to write unit tests without being able to use breakpoints.
The link posted by David Gelhar is correct for Xcode 3.
For Xcode 4, things are much simpler. Edit your current scheme and go to the "Test" action. Click the '+' at the bottom and add the test bundle that contains the tests you want to run. Now when you choose Product -> Test, it will run those tests. Any active breakpoints will be hit just like you'd expect.
Using XCode 4.2, (with SenTestKit unit tests as set up by checking the "Include Unit Tests" checkbox when setting up the project), Product->Test wasn't hitting my breakpoints, but Product->Perform Action->Test Without Building seems to do the trick. Hope this helps.
You may have also accidentally disabled "Debugger: Debug Executable" option in Scheme -> Test -> Info
Here's a blog post: Debugging Cocoa application unit tests with instructions for how to do this (for XCode 3 at least; not sure about XCode 4).
Another item to watch for in XCode 4 is that you haven't added the classes being tested to the Unit Test Target as well as the main project. It appears that it's not necessary and it will mess up your ability to have breakpoints hit.
A clue will be warning messages in the debug log when you run. The messages will look like this:
"Class XXX is implemented in both YYY and ZZZ. One of the two will be used. Which one is undefined."
Once I removed the classes noted in the warnings from the unit test target, Xcode started hitting the breakpoints.
You can remove classes from a target by clicking on the .M file, and turning off its membership in the unit test target in the inspector window under "Target Membership".
Related
How to automatically reload Clojure code?
I have watched the presentation. And in there they use some hot swap Clojure technology that reloads code whenever changes are made into source files. I can run the code, but I can not observe the effect of auto reload. How is it possible to reload the code?
the source code.
There are many ways to reload code, depending on the situation:
Emacs/CIDER shortcuts to reload a file. Probably Rich is doing something similar. Also see this: How to reload a clojure file in REPL
watch files and reload the code (figwheel for frontend development does that, test plugins as well as CIDER shortcuts specifically for running tests, boot has a watch task...)
a middleware for the web server you use (ring for example has ring.middleware.reload/wrap-reload for this, pedestal comes with one as well, other webservers like yada play well with component)
a component workflow works also, there is an example of an auto-reloadable system with holy-grail
(I didn't fully re-watch this video, but these notes are from my observations after skipping through the video and making educated guesses)
From what I re-watched of this video it looks like Rich is evaluating the code in a running repl. This allows him to change the code, evaluate it, and see different behavior.
Many editors have support for evaluating code in a buffer in a Clojure repl. Here is some documentation on using CIDER with Emacs to get to interactively play with your code.
Unrelated to the video in question, if you are using ring for web development. You can use the wrap-reload middleware to have your code automatically reloaded when a file has changed and a request hits your web app. This is extremely useful when developing a Clojure web application.
For automatically reloading and running your clojure.tests I recommend lein-test-refresh. It is a Leiningen plug-in that monitors your project for file changes and when something changes it reloads and runs your tests. If you have tests for your project this greatly speeds up development.
Use mount to manage the starting and stopping of your components. For example in a backend web app, you'll want to startup the db before you start the webserver probably.
Then in emacs you can have:
(defun cider-repl-refresh ()
(interactive)
(save-some-buffers)
(with-current-buffer (cider-current-repl-buffer)
(goto-char (point-max))
(insert (concat "(require 'clojure.tools.namespace.repl) "
"(clojure.tools.namespace.repl/refresh)"))
(cider-repl-return)))
If you are not super fond of Emacs (I love Emacs, but hey not everybody does) LightTable is a very nice option for Clojure/ClojureScript interactive programming too.
For developing ClojureScript (Clojure that compiles to Javascript) LightTable and Figwheel are a really nice pair.
In my opinion LightTable has some advantages against Emacs (I never got cider to work perfectly with ClojureScript) for the webdev side, LightTable is basically a specialized version of Chrome, because it is built on top of Electron.
Check this documentation on the Figwheel GitHub page: Running Figwheel with LightTable:
If you are using Cursive IDE in IntelliJ, there is a special REPL tool which you have to setup to get the functionality you are looking for. It has many features vs. "lein repl" in a terminal window.
Full tutorial here: https://cursive-ide.com/userguide/repl.html
However, its very easy to setup a default instance:
Right click project.clj/deps.edn -> "Create Repl for...". Default settings are fine. Hit ok/apply.
Right click project.clj/deps.edn -> "Run Repl for..." (a repl window will open)
See Tools->Repl for a list of commands, such as:
switch to repl window: Ctrl+\
reload current file in repl: Alt + Shift + L
send function defn to repl: Alt + Shift + M
... and more
In addition you'll get full code completion, syntax highlighting, etc. when writing in a REPL.
In my project that is using Objective-C and Swift I have noticed that suddenly all tests in the Test navigator turned purple with “rT” icon:
I did some digging and I found out that they are runtime discovered tests. These tests are not discovered before you run them. Because of that I have to run all set of test when I add a new test. Code completion in the test target stopped working too. I also can't trigger a test with the little triangle icon offered inside the test class. I tried different suggestions - deleting derived data, deleting xcuserdata, cleaning the project, but still no luck. I am using the latest Xcode 7.3. Any others suggestions would be appreciated?
I am playing around with the new UI testing introduced in Xcode 7 beta. In one of my UI testing scenarios, I need to add some code that does the same thing as clicking Simulator -> Reset Content and Settings in the setup() of my test file, which is a XCTestCase. Can the reset be done programmatically? Or, can we mimic the effect of a factory reset on an app in test code?
Not entirely programmatically, but you can always write a bash file to delete:
${user.home}/Library/Application Support/iPhone Simulator/${simulator.version}
That will clear the settings on the simulator.
My understanding is that you won't be able to that from within your app, as apps are sandboxed.
Usually people were using shell scripts or apple scripts. However, using hard reset is absolutely not necessary.
You shouldn't care about data in other apps, you should care only about the data in your app. You can always delete your app data (files, user defaults) in the beginning of your tests. So, why should you do a hard reset?
A better solution is mocking. If your test supposes that, for example, some variable in NSUserDefaults is not set, you don't have to care about the actual value stored there, just mock the method your implementation is using (e.g. objectForKey: and let it return nil.
I've got the following code in a thread in my application:
while (true) {
if (ready) {
progressIndicatorController.value++;
return;
}
}
The ready variable is changed from a delegate method. This code works great when I open the application by clicking the "Run" button in Xcode's toolbar. However, if I open this application's .app (which I create by clicking Product > Archive and then following the steps) this code somehow doesn't work anymore.
progressIndicatorController.value is never incremented and this if-statement never evaluates to true. What could cause this problem?
This is probably caused by optimization from the compiler.
When you build with Archive, XCode enabled optimization in the compiler that could throw this kind of code away. I think setting the ready variable to volatile could fix your problem, altough if I were you I'd just try to rewrite it so it doesn't trigger this problem.
You can test with optimization turned on by choosing Edit Schemes in the scheme dropdown. Then set Build Configuration to Release in the Run MyApp.app. Don't forget to set it back to Debug when you're done though, as the debugger gets somewhat confused when optimization are on (i.e. you can't see the value of most variables, some breakpoints may behave erratically, etc...)
I want to run tests in Xcode 4 using OCUnit without launching the simulator. Please, don't try and convince me I am doing unit testing wrong or anything like that. I like to do TDD the traditional way: write the API for the class in the tests, then make the class pass the tests. I will write separate tests that are end-to-end that run in the simulator.
If there's no way to do this, then please can someone tell me how to have the test harness not instantiate the whole app? My app is event driven, and it sends a bunch of events through when it starts up that mess with my tests.
Please can someone tell me how to have the test harness not instantiate the whole app? My app is event driven, and it sends a bunch of events through when it starts up that mess with my tests.
I use Xcode 4's built-in testing. App instantiation may seem like a pain, but as I write on Xcode Unit Testing: The Good, the Bad, the Ugly, it makes it possible to write tests without distinguishing between logic tests and application tests. Specifically, it lets me write unit tests for view controllers.
Here's what I do to avoid my full startup sequence:
Edit the scheme
Select the Test action
In "Test" select the Arguments tab
Disable "Use the Run action's options"
Add an environment variable, setting runningTests to YES
Edit your app delegate
Add the following to -application:didFinishLaunchingWithOptions: as soon as it makes sense to:
#if DEBUG
if (getenv("runningTests"))
return YES;
#endif
Do the same for -applicationDidBecomeActive: but simply return.
Update: I have changed my approach. See How to Easily Switch Your App Delegate for Testing.
In the last xcode version (5.0.2) you can do this in very easy way. Choose your Test target, "General" tab. Set "None" in field "Target". Then tap on "Build phases" tab and remove your Main target from "Target dependencies".
In your situation, I am assuming that you have a separate Logic Tests and Application Tests target (if not - you need to). In your schemes configuration you define which targets are built for the 'Test' scheme. If your application tests are not running, the simulator will not launch.
I suspect that you might be trying to run 'logic tests' in an 'Application tests' target (such as the one created by default by Xcode). See more about this difference here (and how to set ut up).
It was pointed out in an earlier answer that logic tests are the right thing to do for this scenario. I had very tough time in getting the logic tests working with XCode Version 4.3.2 (4E2002). Looking at Apple's sample unit test project helped me to understand how to do this with a clear separation. In that example, logic tests test files from the library target, not the application target. The model was encapsulated into a library which was then linked with the main target and logic tests target. The application target contained only views and controllers.
Based on this model, this is what I did to get my logic tests work correctly. Create a new target (Cocoa Touch Static Library) and move all files to be logic tested (typically all your models) to this new target. Under "Build Phases" settings add this new library in "Link Binary With Libraries" of your application target and logic tests target.
I can imagine that these instructions are little confusing. If you dissect the sample project that is mentioned above you will get a better idea.
Note, untested on Xcode 5.
I used #jon-reid’s answer, but found that Xcode adds environment-variables to the xcuserstated part of XcodeProjects, and these are user specific and not typically committed to the repository. Thus I swizzle my AppDelegate to override its loading:
#implementation MyAppDelegate (Testing)
+ (void)initialize {
SEL new = #selector(application:didFinishLaunchingWithOptions:);
SEL orig = #selector(swizzled_application:didFinishLaunchingWithOptions:);
Class c = [self class];
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, new);
if (class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
class_replaceMethod(c, new, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
} else {
method_exchangeImplementations(origMethod, newMethod);
}
}
- (BOOL)swizzled_application:(id)app didFinishLaunchingWithOptions:(id)opts {
return YES;
}
#end
Note, that the following is simpler and still works, though I'm not sure it is reliable:
#implementation MyAppDelegate (Testing)
- (BOOL)application:(id)app didFinishLaunchingWithOptions:(id)opts {
return YES;
}
#end
This works because categories of methods in dynamically loaded components (like the testing bundle) take precedence. Swizzling feels safer though.
Using xCode 7 and xctool
xctool is capable of executing unit tests without the simulator.
To get this working,
1 . Update the target settings run without a host app.
Select your project --> then test target --> Set the host application to none.
2. Install xctool , if you don't have it.
brew install xctool
3. Run the tests using terminal with xctool.
xctool -workspace yourWorkspace.xcworkspace -scheme yourScheme run-tests -sdk iphonesimulator
i've used GHUnit to create osx/ios compatible test suites. there are a few issues, but i found it was more reliable/compatible/straightforward than OCUnit.
GHUnit provides basic template projects for OS X and iOS, which makes initial setup simple.
Note: I generally just use my own kit for most of my testing.