iPhone command line Unit Tests (and File I/O) - iphone

The short question is: How can I get iPhone (objective-c) file operations to work correctly from a command line Unit Test?
The long question, with explanation: This will eventually become a script to perform automated building/testing for my iPhone build, via a Hudson instance. Following makdad's link on this SO question has allowed me to run Unit tests from the command line (semi) successfully.
However, one of my tests fails. The test would call a Caching Service class to save a file, then try and retrieve it. however, file I/O appears to not work when running the tests from the command line :(.
For Reference, running the Unit tests via the Xcode GUI results in no such errors.
I am using NSFileHandle method calls to get handles for writing. if they return nil, the file is created using
[[NSFileManager defaultManager] createFileAtPath:filePath contents:nil attributes:nil];
I thought it may have to do with the spaces in the path to the simulator's cache directory. am I on the right track? if so, how would i rectify this?
Note also that the simulator needs to be NOT running already in order for this to work, the simulator is started programmatically and does not display a GUI. if it is running, the command line build fails.

First: 'the simulator needs to be NOT running already in order for this to work'
I have my tests running in the terminal and it doesn't matter if the simulator is on.
Maybe some build settings you have to look at are: TEST_HOST and BUNDLE_LOADER.
I leave them empty in my xcodeproj.
Note: I'm using Hudson as well with test reports and code coverage.
Second:
I have experienced failures in tests terminal and application with loading paths. This was related to the Core Data model which is loaded from a resource.
The solution was to load the file from url instead of a path:
[[NSBundle bundleForClass:[self class]] URLForResource:....];
I cannot ensure this relates to the same problem your encountering with the NSFileManager, but i can only imagine that NSBundle makes use of the NSFileManager. (So this can be related)
Third:
Do not make your tests dependent on I/O.
I find that that is not the purpose of a Unit Test. Such test may not rely on a filesystem, database, network connection, etc.
Make an file system abstraction class that you mock while running your tests.
This way your implementation is only at one place relying on the actual file system, which you can replace during testing.
You only need one test to check that abstraction.
Summary
The first will improve your test setup.
The second will hopefully solve your test problem.
The third will reduce the occurrence of the problem and improve your code.
Hope this was helpful.

Related

Is flutter test file important?

flutter object has file called "test" who including "widget_test.dart" when I delete this file nothing happens to my app and still working
is this file important to my project or I should delete it
It's a file for putting your unit tests in. It's not necessary for your code to run, but you'll become a much better developer and write much better code if you incorporate unit testing into your workflow.

Error on a .exe that was running perfectly before being compiled

guys,
I just finished a particular code in MATLAB R2014a that reads and write into multiple text files and saves an image inside the same folder of the script. The script runs perfectly, but the compilation executable does not, so I believe that it has something to do with the PATH that the executable is trying to use to run, I don't really know.
The error was the folllowing:
That's the second read function in the code that tries to read a file and it's possible to see that the code was already successful doing a read/write operation, since a .txt is created.
Just to keep it simple, I didn't use any global paths to the files and tried to keep them inside of the script and executable folder.
I don't have a lot of experience compiling stuff, so I just used deploytool and hit run to test it, so I would love to hear some insights about the possible cause of the problem.
Thank you in advance for the help!
MATLAB doesn't include every file on your PATH when it compiles. It tries to detect additional files that may be accessed when running the code in your application's main file, and include those in the compilation, but it isn't always 100% successful (I'm not sure exactly what conditions it's unable to detect).
After you have run the deploytool once, the full list of files it has detected in this way will be listed under Files required for your application to run. You can add files to this list (whether or not your project has already been compiled) using the "+" icon in the corner of that section.

Making and Interfacing with Custom Services

I've been searching for this for awhile now, and I am not sure if I am just not using the correct search terms or if the answer is really that hard to find.
What I am trying to do is to create a new Windows service for a game server from a batch file, and then have a task run another batch file every 30 minutes or more that would run two commands on the game server's command line and do some file work.
Specifically, I am running a Minecraft server using Bukkit for a gaming community I help run, and I want to make sure that the thing is always up unless I specifically tell it to stop (like a service). Bukkit is run directly from a batch file and has it's own command line thing running on it.
I am told that you CAN run this type of thing as a service, but the command line will be hidden from view and/or interaction. This is the second part of my query. I have a handy little backup.bat file that copies all the world files and userdata files into a backup directory, 7zips it, and deletes the directory. The only thing is, is that Minecraft likes to always have the worlds' region files open and writing at all times, meaning that it could cause map corruption if I just run it straight off. To compensate, I need to run the command "save-off" on the server to disable the file hooks temporarily, run the backup, and as soon as it finishes, run "save-on" so that the game can continue without lost data.
What I would like to know about this second one is, is it possible to interface with the game service through a batch file, or do I need to create an application to do that? If the latter, how exactly does one go about doing that? I have moderate C++ knowledge (up through my second OO-C++ course in college), and can possibly learn another language if absolutely necessary.
So, in short, two questions:
1. Is it possible to, and how to run a BAT file as a Windows Service?
2. How to interface with said service via BAT files, and if not possible, what kind of application do I need to write (redirection to or writing a tutorial works for me).
Thank you in advance for any and all help!
Old question, user account doesn't seem active on SO anymore, but hey, if you stumble upon this because you have a similar problem:
Since we are speaking about a Bukkit Minecraft server, turn to the "Essentials" plugin for Bukkit.
It now includes a Backup function that does exactly what the OP asks for, namely stop the save so the files can be manipulated without corruption, launch a script, then starts again.
The script can be a backup one (examples provided in the linked page) but can be used to run any operation on the world's files.

How to run and debug unit tests for an iPhone application

NOTE: Unit testing is a lot easier to setup nowadays. This tutorial is not really relevant for Xcode version 5 and above.
It took me quite some time but I finally managed to make it work for my project.
To create the "logic" tests I followed Apple guidelines on creating logic tests.
This works fine once you understand that the logic tests are run during build.
To be able to debug those tests it is required to create a custom executable that will call those tests. The article by Sean Miceli on the Grokking Cocoa blog provides all the information to do this. Following it however did not yield immediate success and needed some tweaking.
I will go over the main steps presented in Sean's tutorial providing some "for dummies" outline which took me some time to figure out:
Setup a target that contains the unit tests but DOES NOT run them
Setup the otest executable to run the tests
Setup the otest environment variables so that otest can find your unit tests
The following was performed with XCode 3.2.5
Note for XCode 4
In XCode 4 it is possible to debug your unit tests DIRECTLY. Just write your test, add it to your target as one of the tests and set a breakpoint in it. That's all. More will come.
Step 1 - Setting up the target
Duplicate your unit tests target located under your project Targets. This will also create a duplicate of your unit tests product (.octest file). In the figure below "LogicTest" is the original target.
Rename both the unit tests target and the unit tests product (.octest file) to the same name. In the figure below "LogicTestsDebug" is the duplicate target.
Delete the RunScript phase of the new target
The name of both can be anything but I would avoid spaces.
Step 2 - Setting up otest
The most important point here is to get the correct otest, i.e. the one for your current iOS and not the default Mac version. This is well described in Sean's tutorial. Here are a few more details which helped me setting things right:
Go Project->New Custom Executable. This will pop open a window prompting you to enter an Executable Name and an Executable Path.
Type anything you wish for the name.
Copy paste the path to your iOS otest executable. In my case this was /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator4.2.sdk/Developer/usr/bin/otest
Press enter. This will bring you to the configuration page of your executable.
The only thing to change at this point is to select "Path Type: Relative to current SDK". Do not type in the path, this was done at step 3.
Step 3 - Setting up the otest arguments and environment variables
The otest arguments are straightforward to setup... But this proved to be my biggest problem. I initially had named my logic test target "LogicTests Debug". With this name and "LogicTests Debug.octest" (with quotes) as argument to otest I kept having otest terminating with exit code 1 and NEVER stopping into my code...
The solution: no space in your target name!
The arguments to otest are:
-SenTest Self (or All or a test name - type man otest in terminal to get the list)
{LogicTestsDebug}.octest - Where {LogicTestsDebug} needs to be replaced by your logic test bundle name.
Here is the list of environment variables for copy/pasting:
DYLD_ROOT_PATH: $SDKROOT
DYLD_FRAMEWORK_PATH: "${BUILD_PRODUCTS_DIR}: ${SDK_ROOT}:${DYLD_FRAMEWORK_PATH}"
IPHONE_SIMULATOR_ROOT: $SDKROOT
CFFIXED_USER_HOME: "${HOME}/Library/Application Support/iPhone Simulator/User"
DYLD_LIBRARY_PATH: ${BUILD_PRODUCTS_DIR}:${DYLD_LIBRARY_PATH}
DYLD_NEW_LOCAL_SHARED_REGIONS: YES
DYLD_NO_FIX_PREBINDING: YES
Note that I also tried the DYLD_FORCE_FLAT_NAMESPACE but this simply made otest crash.
Step 4 - Running your otest executable
To run your otest executable and start debugging your tests you need to:
Set your active target to your unit test target (LogicTestsDebug in my case)
Set your active executable to your otest executable
You can build and run your executable and debug your tests with breakpoints.
As a side note if you are having problems running your otest executable it can be related to:
Faulty path. I had lots of problem initially because I was pointing to the mac otest. I kept crashing on launch with termination code 6.
Faulty arguments. Until I removed the space from bundle (.octest) name I kept having otest crash with exit code 1.
Wrong path in environment variables. Sean tutorial has lots of follow-up questions giving some insight on what other people tried. The set I have now seems to work so I suggest you start with this.
You may get some message in the console which might lead you to think something is wrong with your environment variables. You may notice a message regarding CFPreferences. This message is not preventing the tests from running properly so don't focus on it f you have problems running otest.
Last once everything is working you will be able to stop at breakpoints in your tests.
One last thing...
I've read on many blogs that the main limitation of the integrated XCode SenTestKit is that tests cannot be run while building the application. Well as it turns out this is in fact quite easy to manage. You simply need to add your Logic tests bundle as a dependency to your application project. This will make sure your logic tests bundle is built, i.e. all tests are run, before your application is built.
To do this you can drag and drop your logic test bundle onto your application target.
This post is intended as a "How-to" more than a real question. Therefore this answer is just meant to allow me to mark the "How-to" as "answered". This will probably be flagged by the community as irregular. I'm up for suggestions on where to post future "How-to" articles.
One final note though on this topic.
For those who still wonder whether writing unit tests is worth it I would definitely say Yes!
I am currently writing an application with CoreData and retrieval of data from a web service (xml parsing). The complete model can be tested and debugged without having to:
run the actual application on the simulator or device. Not having to use the device to run the tests is a huge gain of time. It's the difference between 2 minutes and 5 seconds per run.
without the need to create views or controllers when testing the model. The complete development and testing can focus on the model only in the first iteration. Once the model is cleared for integration the rest of the development can follow.
To debug the xml parsing I can simply use "hard-coded" files which I completely control.
The crux is of course to write the tests as you implement features in the code. It really is a time saver down the line in terms of debugging of the complete application.
VoilĂ , I'll leave it at that.
I was able to run the test case in debugger in the following simple steps:
Product > Build For > Testing
Put a break point in part of the test you want to debug
Product > Test
This is on Xcode 6.0.1 and seems much more convenient than the long procedure described above.

How can I write to the current directory in the iPhone SDK when running xcodebuild from the command line?

Does anyone know how to obtain the path to the current directory when running xcodebuild (mainly, the project directory) and write files to it? I'm trying to save the results of some unit tests to disk from my obj-c code, but I'd rather not dump them deep in the app's document path if possible. I might be able to append '../../..' etc. to the document path, but I was hoping there might be a more elegant method.
*This is relevant only to the simulator, of course... but perhaps even the simulator attempts to maintain the iPhone file system sandbox? I've had no luck writing to other random locations on my Mac, so I suspect that might be the case.
Thanks for your input!
I figured this out - the answer is embarrassingly simple. With an emphasis on "embarrassing".
If you use something like NSString's writeToFile methods, all you need to do is think of your path as relative to wherever you're running xcodebuild from - no NSSearchPathForDirectoriesInDomains needed.
Example:
(if running in ~/src/awesomeapp)
[myString writeToFile:#"awesome.file" atomically:YES encoding:NSUTF8StringEncoding error:&error];
Will output to:
~/src/awesomeapp/awesome.file
Yes, I am an idiot. I actually tried this first, but I was attempting to write to a relative directory that didn't exist, thus resulting in an unhelpful "Cannot do this" style error that led me all around the internets and eventually to stackoverflow... (you need to use FileManager#createDirectoryAtPath! There is no automatic path creation, unfortunately.)
FYI, as should be apparent, you are free to write files wherever you wish on your hard drive when running via xcodebuild - no sandboxing occurs. If you run in the simulator, though, it might be a different story.