Run unittests with a specific locale (en_US or none) - ios

Is there a way to force a specific locale when running unittests?
Eg. always use en_US or force no locale, so that none of the .lproj files are loaded.
My unittest is sensitive to the currently selected language in the Settings app (in the iOS Simulator). Preferably I would like my unittests not to be language sensitive.
Below is my unittest code that shows the problem
#interface MYGalleryTests : SenTestCase
#end
#implementation MYGalleryTests
-(void)test0 {
// This test doesn't work.
// I get 'No pictures' when locale is en_US
// I get 'Ingen billeder' when locale is da_DK
NSString* actual = [MYGallery emptyMessage];
NSString* expected = #"EMPTY_MESSAGE";
STAssertEqualObjects(actual, expected, nil);
}
#end
#interface MYGallery : NSObject
+(NSString*)emptyMessage;
#end
#implementation MYGallery
+(NSString*)emptyMessage {
return NSLocalizedStringFromTable(#"EMPTY_MESSAGE", #"Gallery", #"Message shown when gallery is empty");
}
#end
en.lproj/Gallery.strings
/* Message shown when gallery is empty */
"EMPTY_MESSAGE" = "No pictures";
da.lproj/Gallery.strings
/* Message shown when gallery is empty */
"EMPTY_MESSAGE" = "Ingen billeder";

There is a way to run the unit tests in a specific locale, but it isn't good for unit testing, but it can be useful for testing.
In Xcode, go to Product -> Scheme -> Edit Scheme… -> select Test -> Options and then set the 'Application Language' popup to the desired language. Then your unit tests will run in the specified language. You can use this to test code for a specific locale. You can use this to get faster test turnaround than actually running your app, especially if you only run a specific subset of unit tests. However, it is not useful for unit testing in general because you're limited to the specified language.
Also, doing this will modify your .xcscheme, so you'll need to change that back when you're done.
One way to change the locale for unit testing is to use the technique specified here. However, that technique uses method swizzling, which doesn't work with Swift.

Just specify the lang in run options.

Posting a proper answer so you can mark this as answered.
How to force NSLocalizedString to use a specific language has a solution for this problem.

Related

Cannot resolve enum values by name in Xcode debugger

With an enum typedef'd in a global header file used throughout my project, I am unable to refer to the individual enum values by name while using lldb in Xcode.
For example, if I am stopped at a breakpoint anywhere the enum type is available, and I try to evaluate something at the lldb prompt in Xcode (e.g. (lldb) p (int)EnumConstant), lldb complains:
error: use of undeclared identifier 'EnumConstant'
Furthermore, if I try to set a conditional breakpoint using an enum constant in the condition (e.g. right-click breakpoint in Xcode > Edit Breakpoint... > Condition: EnumConstant == someLocalVar), then Xcode complains every time it tries to evaluate that condition at that breakpoint:
Stopped due to an error evaluating condition of breakpoint 1.1: "EnumConstant == someLocalVar"
Couldn't parse conditional expression:
error: use of undeclared identifier 'EnumConstant'
Xcode's code completion popover even resolves a suggestion for the enum constant when I begin typing the name in the "Edit Breakpoint..." window, so Xcode itself doesn't have a problem resolving it.
Is there an option I can set in lldb or Xcode so that lldb maintains the enum identifiers after compilation? I'm assuming the enum constants get translated to their ordinal value during compilation, causing the executable to discard the identifiers, but thats just my naive speculation.
When I use the equivalent code in a simple GNU C program in Linux or Cygwin (minus the class definitions obviously), but using gcc/gdb instead of Xcode/lldb, I don't have these problems. It is able to resolve the enum values no problem.
I've created a tiny Xcode iPhone project to demonstrate what I mean. Using any of the enum_t constants below within the ViewController.m context (the for-loop is a good place to demo) will produce the same results.
ViewController.h:
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController
typedef enum
{
eZero, eOne, eTwo, eCOUNT
}
enum_t;
extern NSString const * const ENUM_STR[];
#end
ViewController.m:
#import "ViewController.h"
#implementation ViewController
NSString const * const ENUM_STR[eCOUNT] = { #"eZero", #"eOne", #"eTwo" };
- (void)viewDidLoad
{
[super viewDidLoad];
for (enum_t value = eZero; value < eCOUNT; ++value)
{
NSLog(#"%-8# = %d", ENUM_STR[value], value);
}
}
#end
This is a bug (fairly longstanding) in how the name->Debug Information lookup-accelerator tables for enums are built. While enum types are listed, enum values are not. That was surely done to save output debug info size - debug information gets quite big pretty quickly, and so there's a constant tension between the cost of adding more info and the utility of that more info. So far this one hasn't risen to the level of inclusion.
Anyway, doing a search through "all debug information for anything with a name that matches 'eZero'" is prohibitively slow even for decent sized projects, and gets really bad for large ones. So lldb always uses these name->Debug Info tables for its first level access.
Because the accelerator tables do contain the enum type by name (and more important for you typedefs by name as well), the workaround is to do:
(lldb) expr enum_t::eZero
(int) $0 = 0
Of course, if you have truly anonymous enums, then you are pretty much out of luck till this info gets added to the accelerator tables.
BTW, the Xcode symbol completion in the Debugger Console window is done using the Xcode SourceKit indexer, not lldb. So the completions offered from Xcode are not a reflection of lldb's knowledge of the program.
BBTW, gdb doesn't use compiler-made accelerator tables (these were an Apple extension up till the new DWARF 5 standard) but manually builds an index by scanning the debug info. That allows them to index whatever seems best to the debugger. OTOH, it makes debugger startup quite a bit slower for big projects.

swift #pragma replacement to stub out code in production vs dev (ie #if TEST_CODE == 1)?

I have test code that I use for GPS testing of my app that I want
to stub out entirely so that its not even compiled into the binary.
Its a simple way to turn on/off testing throughout the codebase for
various things I wish to test.
in Objective-C I would do:
#define TEST_CODE == 1
and use it like this for example:
- (void) viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
#if TEST_CODE == 1
addressTextField.text = #"My Real Address";
#endif
...
}
Since binaries can be searched with things like the 'strings' command,
I don't want any of my test stuff to reach production, however AFAIK
there is no way to do that in swift.
Does anyone have any solutions that would do this?
It seems like a deficiency of swift not to have some type of mechanism
to do so. I can't be the only one who uses #pragma's in this way.
The equivalent in Swift is conditional compilation.
You can set your conditional flag as -DTEST_CODE in the OTHER_SWIFT_FLAGS build setting for your Debug configuration. Then, you can refer to it from Swift files as such:
#if TEST_CODE
// conditionally do something
#endif
Note that there is no support for flag values, so you cannot pass the value 1.
For more information: Using Swift with Cocoa and Objective-C (Swift 4): Preprocessor Directives
Original source of the information kitefaster site

Show debug messages if argument is set

In my project i'm showing debug messages with global variable:
struct GVariables {
static let debug = false
}
if GVariables.debug {
print("Debug mode enabled")
}
But is it possible to set argument here:
and check debug argument in code. How can i do this ? And is this a correct way ?
You can get access to those launch arguments and environment variables via NSProcessInfo
if NSProcessInfo.processInfo.arguments["DEBUGRPM"] ...
That's not unreasonable and allows you to change the behavior of a compiled app which can be useful in some cases. It does however have some overhead since you're always performing this check. If you would only ever enable debug logging in a debug build then setting a value in "Swift Compiler - Custom Flags" (as shown in the question #Larme linked) and using an #if DEBUGRPM expression will give you conditionally compiled code, saving the app the work of performing a runtime if test.
Which approach is more reasonable for you will depend on how you plan to use and when you plan to toggle this behavior.

how to get value from source code using calabash iOS

I am using calabash cucumber to test my IOS application. The issue is for doing validations and some other operations. I need to get value from the source code. Is it possible? If so, how? Please help me. I have gone through different documentations, but I did not get a proper answer. Thanks in advance.
You can using the calabash-ios query language to call selectors on UIView and its subclasses.
If you have any experience with calabash-ios you probably have been using this feature without realizing it.
# calls the 'text' selector on the labels that match the query
query("label marked:'product description'", :text)
To see if a button is enabled, you could do the following:
# NB the property is 'enabled', but the selector is 'isEnabled
query("button marked:'ask for help'", :isEnabled")
This is described on the calabash-ios wiki:
https://github.com/calabash/calabash-ios/wiki/03.5-Calabash-iOS-Ruby-API
https://github.com/calabash/calabash-ios/wiki/05-Query-syntax
If you want to set custom attributes then one way to do it is to subclass a UI element (such as UIButton and then you can create a property which you can then access like so:
ExampleButton.h:
#interface ExampleButton : UIButton
{
BOOL doingSomething;
}
#property (nonatomic) BOOL isDoingSomething;
ExampleButton.m
#import "ExampleButton.h"
#implementation ExampleButton
... //code possibly here
- (BOOL)isDoingSomething
{
return doingSomething;
}
... //more code possibley here
and then you would have other code that sets doingSomething.
By the way I've only just started out in iOS and Calabash testing so I my objective C is rusty, but I think you can also not have the doingSomething Bool and just have #synthesize isDoingSomething which you can then get and set on the property directly (self.isDoingSomething = true; etc).
In calabash your query would look like this then:
query("view:'ExampleButton' isDoingSomething:1")
or
query("view:'ExampleButton' isDoingSomething:0")
to see if the property is true or false respectively.
This is probably not the only way to do it (it probably isn't even the easiest way to do it but it works).

Check if the running code is unit test case or not

I want to check if the running code is unit tese case or not execute different code for the result such as:
if ( unit test case is running )
{
do something
}
else
{
do other thing
}
any idea on this?
This is a bad approach you should try to simulate logic parts which you are trying to avoid by this statemetn through Mock ojects or other mechanism.
Now to your question you can use a oolean variable like isUnittest which you set on test setup and Teardown, ut as saied i dont recommend you doing this.
This seems to work for me (iOS 8, Xcode 6):
- (BOOL) isRunningTest {
return NSClassFromString(#"XCTestCase") != nil;
}
I think this is cleaner and easier than other answers.
Another way is to let the class have customizable behavior controlled via a static method, and have test case call that method in its static load method.
I had a similar issue using storyboard and an external restful service for authentication via oauth. The app delegate would check if there is a valid oauth token in appdelegate:didFinishLaunchingWithOptions, and if not, then programatically trigger segue to do the oauth login. But this was not desirable in test cases. To solve this, I created a static method within the app delegate to disable the login screen. This is the code within my app delegate:
static Boolean showLoginScreen = TRUE ;
+ (void) disableLoginScreen
{
showLoginScreen = FALSE ;
NSLog(#"disabled login screen") ;
}
The test case had its load method to do the following:
// disable login screen for the test case
+ (void) load {
NSLog( #"now disabling login screen" ) ;
[XYZAppDelegate disableLoginScreen];
}
This worked because the test case class was loaded before application was initialized. Of course you must check the value of this flag within app delegate to trigger/not trigger the login segue. Other alternatives I tried but rejected were as follows:
Create a preprocessor define on the test target. But the compiler only compiles the test case files with this flag, not the application source. See http://www.innovaptor.com/blog/2013/09/02/xcode-preprocessor-macros-for-test-code.html
Use the static initialize method of the test case to call the disable method. On test case run, the application is started before the test case class is loaded. See http://www.friday.com/bbum/2009/09/06/iniailize-can-be-executed-multiple-times-load-not-so-much/ for some details.
Don't message UIAlertView directly. Instead, use dependency injection, for example, a property like
#property (strong, nonatomic) Class alertViewClass;
Then your code to create an alert can do
UIAlertView *alert = [[_alertViewClass alloc] initWithTitle:…etc…];
In your test code, inject a different class. I use https://github.com/jonreid/JMRTestTools to specify JMRMockAlertView. I can then test the alert calls with JMRMockAlertViewVerifier. (In fact, this enables test-driven development of alerts.)
Edit: These days, I use https://github.com/jonreid/ViewControllerPresentationSpy

Resources