Dynamic "test host" or bundle loader for iOS Unit Testing? - ios

How do I make the test host/bundle loader dynamic based on the current scheme? Right now the value is set to:
$(BUILT_PRODUCTS_DIR)/MyApp1.app/MyApp1
The problem is I have 4 apps in the workspace and I would like to use the same unit testing suite for all of them. How do I dynamically change the "MyApp1" part based on the current scheme? Is it an environment variable based during build? I tried setting it to things like $(PROJECT_NAME) but those seem to get the name of the test suite.

To do this you need to have a variable inside the build settings - which seems simple, but it's not. If you set an environment variable through a Pre- or Post- step in the application or test scheme, it does not seem as though it will be picked up here. The build settings, after all, happen before the build. Same is true of a preprocessor macro, though doing this using xcodebuild and passing in a custom option may work.
The only way I know of to do this is to use an xcconfig file. Create one and apply it to (at the least) your test target. The content should include something like this:
THINGUNDERTEST=FooBar
Now in your project settings, wether in an xcconfig or the project file, set BUNDLER_LOADER to:
$(BUILT_PRODUCTS_DIR)/$(THINGUNDERTEST).app/$(THINGUNDERTEST)
That will work. Now you can change THINGUNDERTEST through various means and get at least some dynamic behavior. This may work for you or may not, depending on your needs - but it probably only a starting point.

Related

Different variable value for development and Ad-Hoc/Production in iOS?

In my project there is a variable(Int) value that I want to be different for development and Ad-Hoc/Production because it's hard to test app with large number(100) for that value, so I changed it to 3 to test but now problem is that I have to build app frequently and some time I forgot to change the value back to 100 so is there any way to make this process automated ?
Use different build configurations as described here: http://limlab.io/swift/2016/02/22/xcode-working-with-multiple-environments.html
Targets are usually used for different apps sharing the same code base. For example: Lite and Pro versions of an application or Watch extension etc.
Update:
https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Targets.html
A target specifies a product to build and contains the instructions for building the product from a set of files in a project or workspace.
As I already mentioned, targets are usually used for different products which behave different. In your case you duplicate build setting, phases etc. for a single variable you want to be different.
https://developer.apple.com/library/content/featuredarticles/XcodeConcepts/Concept-Build_Settings.html
A build setting is a variable that contains information about how a particular aspect of a product’s build process should be performed.
It is quite enough to manage "different environments" for a single target in order to achieve what you want.

Optional file dependencies in Bazel?

Is there a way to specify optional dependencies in Bazel?
I'd like to make a rule to somewhat mirror Kitware's ExternalData, but I would like to see if I can enable workflows where the developer edits the file in-tree, ideally without needing to modify the BUILD file.
Ideal Workflow
Define a rule, external_data, which can fetch a file from a given server given its SHA-512.
If the file already exists, check it's SHA-512.
If that is what is requested, symlink / copy this file (ensuring that no tests can modify the original file).
If it is different, print a warning, but proceed as normal, to allow for developers to quickly modify the large files as they need.
I would like to do this such that Bazel can switch between the file being present and not, and be robust to false-positives on caching. An example scenario that I would like to avoid, if I were to not include it as an optional dependency:
In a prior run, the file was in the workspace, Bazel built the target, everything's fine and dandy.
Developer removes the file from the workspace after uploading, satisfied with their changes and wanting to test the download process.
When running the downstream target, Bazel doesn't care about the change in the workspace since it's not an explicit dependency, and the symlink is invalidated, and the test crashes and burns.
To me, it seems like I'd run into this if I tried to implement a repository_rule rule which manually checks for the file existence, and conditionally executes (I'm not sure if analysis would retrigger this rule being "evaluated" if Step 2 happens.).
Workaround
My current thought for an alternative workflow is to have an explicit option for external_data, use_workspace: if False, it will download the file; if True, it will just mirror exports_files([]). The developer can then set this when modifying files.
(Ideally, I'd like to optionally include a file which indicates the SHA (${file}.sha512), but this seems to go back to the original ask.)
One workaround is to use Bazel's glob(...) method to effectively check for file existence.
If you have a file, say basic.bin.sha512, and you want a rule to switch modes based on that file's existence, you can use glob(["basic.bin.sha512"]), which will either match the package file exactly or return an empty list.
I had tinkered around with using this on larger sets of files, and it appears to work. However, for the time being, I've erred to having a sort-of explicit "development" mode for the target definition to keep the Bazel build relatively consistent, regardless of what files may be checked out.
Here's an example usage:
https://github.com/EricCousineau-TRI/external_data_bazel/blob/4bf1dff/WORKFLOWS.md#edit-files-in-a-sha512-group

Is there is any way to create a IOS app as build for another app?

I have an IOS app which holds lot of Configuration settings to use the app and also this app is used in 5 warehouses, settings will be differ from one warehouse to another warehouse. So it becomes more painful for the users using this app.. Even ever they install the app then need to set the configuration settings.
So my problem is If i hardcode the settings value, it is very difficult to maintain the code for all the different warehouse. if i do small change in my app have to change in all of the 5 source code.. Even if i decide to maintain 1 code .. i have to change the setting value every time before setting the build.. It is more painful for me.
so my question is..
Is there any way to run a app and set values in configuration settings. And generate this setting app as a build ?? i don't know it will workout or not please share me some ideas..
If I understand correctly, you want to have 1 source code and there is possibility to create different Targets. Each target can have it's own configuration plist file and you can set also different preprocessor macros for each target.
How to use preprocesor macros you can see here: How can I differentiate between multiple targets in xcode at runtime
How to create targets you can see here: Add preprocessor macro to a target in xcode 6
One more possibility (besides targets) is to create a shared library and if you want to apply some configs after installation you can prompt user to download one from a server (for instance)
Yes, you can create different schemas.
For example, you can create an application for Development, Staging, Production.
You can have configurations in plist file and make it variable according to the schemas.
When your application opens it will take the values according to the schema with which it was built.
Follow this guide to create different schemas.
Also, you can integrate Fastlane to generate builds easily with different schemas with simple commands.
Yes you can have one app with different targets and schema. Then just google it there's many articles about.

XCode Target Duplication via Code

Does anyone know a tried and tested way of duplicating XCode targets programatically?
I've tried this Gist based on the xcodeproj Ruby gem but it doesn't copy all the settings (like it would do if doing it through the XCode UI)
https://gist.github.com/ratazzi/f6d9217654d6605450a0
For anyone reading I've actually taken a different approach with this.
Rather than duplicating targets and changing specific values I've utilised fastlane an in particular the 'set_info_plist' function to change values at build time that are specific to a target.
https://docs.fastlane.tools/actions/#set_info_plist_value
This is useful for things like theming changes as per the build or Free/Paid applications environments where you want one single code base that behaves differently depending on the theme or nature of the application.

Why should I use a separate test target for running XCTests and how should I do that?

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.

Resources