Looking for a decent scheme to implement acceptance tests environment using native Objective-C & Mac technologies
Asked Answered
W

1

6

Background

I am looking for a way to implement a scheme similar to what Frank library uses to implement "Automated acceptance tests for native iOS apps", but I want this scheme rely on native iOS/MacOSX technologies. Sorry for the following TLDR but it deserves verbose explanation.

1. Here is a short overview of how Frank works:

it has Client and Server parts.

Server part is embedded into an application that we want to run acceptance tests against. Frank tutorials show us how to create a duplicate target of an app's main target and embed Frank HTTP server to it.

Client part - is a mainly a Cucumber that runs plain text scenarios: each scenario contains directives that should be run against an app (fill text field, touch button, ensure that a specific element exists on a page etc...). Also each scenario launches its own instance of app by this means providing a fresh state every time we enter a new scenario.

Client (Cucumber and Ruby-to-Objective-C bridge) communicates with Server (HTTP server embedded into an app) via HTTP protocol. It uses special conventions so client can tell server what an app should do so the specific scenario could be performed.

2. Recently I've found the following article written by the author of Frank Pete Hodgson:

http://blog.thepete.net/blog/2012/11/18/writing-ios-acceptance-tests-using-kiwi/

In which he suggests more simple way of writing acceptance tests for the developers who don't like to rely on external tools like Cucumber and Ruby. Let me quote the author himself:

Before I start, let me be clear that I personally wouldn’t use this approach to writing acceptance tests. I much prefer using a higher-level language like ruby to write these kinds of tests. The test code is way less work and way more expressive, assuming you’re comfortable in ruby. And that’s why I wanted to try this experiment. I’ve spoken to quite a few iOS developers over time who are not comfortable writing tests in ruby. They are more comfortable in Objective-C than anything else, and would like to write their tests in the same language they use for their production code. Fair enough.

This blog post inspired me to quickly roll my own very raw and primitive tool that does exactly what Pete described in his blog post: NativeAutomation.

Indeed, like it was described by Pete, it is possible to run acceptance tests by using just Kiwi/PublicAutomation setup placed in a simple OCTests target. I really liked it because:

  • It is just pure C/Objective-C. It was very easy to build initial bunch of C helpers, that look like Capybara helpers:

tapButtonWithTitle, fillTextFieldWithPlaceholder, hasLabelWithTitle and so on...

  • It does not require external tools and languages: no need in Cucumber/Ruby or anything else. NativeAutomation itself uses just PublicAutomation that Frank also uses. PublicAutomation is needed to simulate user interactions on an app's screen: touches, fills, gestures...

  • It is very handy to run these tests right from Xcode by just running a Cocoa Unit Tests bundle. (Though command-line builds are easy as well).

Problem

The problem Kiwi/PublicAutomation approach has is that the whole testing suite is embedded into the app's bundle. It means that after each scenario is run, it is not possible to reset application to force it to be in a fresh state before next scenario begins execution. The only way to workaround this problem is to write Kiwi's beforeEach hook with a method that performs a soft-reset of an application like:

+ (void)resetApplication {
[Session invalidateSession];
[LocationManager resetInstance];

[((NavigationController *)[UIApplication sharedApplication].delegate.window.rootViewController) popToRootViewControllerAnimated:NO];

[OHHTTPStubs removeAllStubs];

cleanDatabase();

shouldEventuallyBeTrue(^BOOL{
    return FirstScreen.isCurrentScreen;
});

but in case of application which involve networking, asynchronous jobs, core data, file operations it becomes hard to perform a real teardown of a stuff left by previous scenario.

Question

The problem described above made me thinking about if it is possible to implement a more complex approach similar to Frank's approach, with a second app that works apart from main app's bundle and does not rely on external tools like Cucumber(Ruby).

Here is how I see the way it could be done.

Besides a main app (MainApp) there is a second iOS (or Mac OS X) app (AcceptanceTestsRunnerApp) that contains the whole acceptance tests suite and runs this suite against a main app bundle:

It does fire up new simulator instance before it enters each new scenario and executes current scenario against current simulator's app's instance.


The question is:

I am not well awared about Mac OSX or iOS technologies that would allow me to do that: I don't know if it is even possible to setup a Mac OS X / iOS application (AcceptanceTestsRunnerApp) that could take a control over a main app (MainApp) and run acceptance tests scenarios against it.

I will be thankful for any thoughts/suggestions that people who feel more comfortable with having native Objective-C tool for writing acceptance tests for iOS applications might have.


UPDATED LATER

...I did read some documentation about XPC services but the irony about it is that scheme I am looking for should be quite opposite to the scheme XPC documentation suggests:

Ideally I want my AcceptanceTestsRunnerApp dominate over MainApp: run it and control it (user interactions, assertions about view hierarchy) via some object proxying to MainApp's application delegate while XPC services setup would assume XPC service (AcceptanceTestsRunnerApp) to be subordinate to an app (MainApp) and will require XPC service to live inside app's bundle which I want to avoid by all means.

...My current reading is Distributed Objects Programming Topics. It seems to me that I will find my answer there. If no one provides me with guides or directions I will post an answer about my own researches and thoughts.

...This is the next step in my quest: Distributed Objects on iOS.

Winona answered 30/10, 2013 at 18:50 Comment(12)
You may be wasting your time with Distributed Objects. I've attempted to use DO in a few projects, and have always been stymied by its limitations and bugs. DO never worked that well, and it hasn't seen any improvement from Apple in years. It also has some well documented limitations. mikeash.com/pyblog/…Toni
If you're targeting the simulator, you might want to look at Sim-Launcher. It's written in Ruby, and used by Frank, but you may be able to look at how it works and create a native Objective-C adaptation. If you need to test on an actual device, you should check out fruitstrap. github.com/moredip/Sim-Launcher github.com/ghughes/fruitstrapToni
I am aware of this Mike Ash blog post. "and have always been stymied by its limitations and bugs." - Could you please provide more details - what limitations and bugs did YOU see I can't know from docs and Mike Ash's post? "you might want to look at Sim-Launcher" - I am aware of it and learned a couple of useful things, thanks! "you should check out fruitstrap" Thanks! Didn't know about that one. Will take it into my notes. Thanks for the answer.Winona
It's been a few years since I used DO (and from what I have heard, there haven't been any changes to DO in that time), so I can't give you concrete examples, but I recall experiencing crashes, both reproducible and random; timing issues; unexplained disconnections (causing the exceptions mentioned in the Mike Ash article); and incorrect return values.Toni
I will take these issues into account. Are there any alternatives to NSConnection/NSDistantObject you might suggest? You advice me not to deal with DO, what is your advice on what I should try/explore? Thanks.Winona
That's a tough question, and probably why there aren't any real answers to this question. Your AcceptanceTestsRunnerApp can't be an iOS app due to various restrictions on iOS. If you were communicating between Mac apps, there would be other options. Frank installs an HTTP server on your iOS app and then connects to it from the Mac, and that's probably the best way to go about it. It's not great. In fact, it kind of sucks, but you're not really going to find an off-the-shelf solution that works well, and you're probably best of rolling your own with Sim-Launcher and/or Fruitstrap.Toni
I wish I had a better answer for you. Personally, I use Frank, and when I started, I had the same problem with teardown. However, as my app got more complex, I embraced using beforeEach steps to get my app into the desired state before running the tests. When I was resetting the app, users were hitting bugs if they did x, then y, then z. Users don't usually reset the app each time they do something. Now I run my tests in random order so I can try to catch any order-dependent bugs.Toni
Thanks for you attention! +1 - it should be a Mac OS app running tests against iOS app - you reproduce my own thoughts here - nothing else is possible here I think. About Frank, besides teardown (yes, it can be workarounded!), I also want 1) native Objective-C 2) more natural helpers for working with view hierarchy (I want to have more access than access by accessibility labels allows - I personally don't like these Shelley and other selector engines) 3) Ability to work with different iOS/iPads, devices very easily out of a box 4) Also I am thinking about GUI tools <continued in next comment>Winona
*tool that would allow overviewing the whole acceptance tests suite, allow selecting build options to run on and so on. I want to make acceptance testing routine as easy as possible. These are the reasons why despite of the fact that I know Frank is obvious default here I want to continue my research to see if I can come up with a decent alternative, at least an alternative that would make my own test automation routine more easy and (probably) productive.Winona
I definitely wish you luck in that endeavor, and I'm sorry I can't suggest something more helpful. Frank actually has an API for you to write your own selector engines, but you're still going to be limited by the accessibility API. That's been good enough for me, since the accessibility API closely mirrors what users see, and it helps me to keep my apps accessible. However, I understand the motivation to have deeper access. You might want to look into forking Frank, changing it to not use accessibility labels, and writing your own selector engine <continued>Toni
At this point, you're still working entirely in Objective-C. You don't actually need to use ruby to use Frank. You can communicate with its HTTP server directly. There are even people who use Java to run their Frank tests, if you can believe it. You'd still have to write your own acceptance test runner that can connect to multiple Frank HTTP servers, and writing your own GUI tools. It might get you close to what you want.Toni
Hm, I didn't think about this option, thanks for mentioning it. I still prefer looking my own native variant, but I will probably consider a "fallback" to this one, if my quest will fail. For now I am pretty intrigued with if it is actually possible to do that "native automation" - somehow I feel that it is - I am thinking about it last week, trying to imagine various combinations of tools in my head - I will update this topic with an answer if/when I come up with something interesting. Thanks for your answers!Winona
D
0

KIF and the port of Jasmine - Cedar to iOS work fairly well from my experience.

However, I also have had lots of good usage out of calabash, which like Frank, is powered by gherkin.

Deprecative answered 23/11, 2013 at 3:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.