4

私は現在、frank (そしてUISpec ) を使用して、新しい iOS アプリケーションの受け入れテストを作成しようとしています。フレームワークは、ビューを操作するための基本的な方法としてタッチをサポートしていますが、現在、より複雑なジェスチャ (ピンチ、スワイプなど) はサポートしていません。少なくともスワイプのサポートを追加する必要があります。これは、アプリケーションの機能の中核であり、それがなければテストはまったく役に立たないからです。

Cocoa でイベントをシミュレートする方法が見つかれば、これを実装するのはかなり簡単です。Apple の UIAutomation フレームワーク (こちらを参照) を使用すると、スワイプ ジェスチャを送信できるため、これらのイベントを外部で生成する例を示します。私はウェブ上を検索しましたが、これを行っている人の例は見つかりませんでした(以前、誰かがこれに似たものを求めていたスレッドがありました...)。

あなたの助け/アイデアを前もって感謝します...

4

1 に答える 1

6

昨日、これを機能させるために費やしたのは、ある種の解決策でした。私はそれに完全に満足しているわけではありませんが、今のところ私ができる最善のことでした-誰かが改善や有効な代替案を提案できるなら、私は彼らを歓迎します...

とにかく、似たようなことをしようとしている他の人のために。この投稿で詳しく説明されている API に基づいてソリューションを作成しました。シミュレートしたい一連のイベントを記録し、それらを再生しました。唯一の問題は、組み込みの再生 API を機能させることができなかったことです (下部に記載されているコメントに記載されているのと同じクラッシュが発生しました)。ASM の土地をしばらく掘り下げた後、私は自分のバージョンを作成することになりました。

@implementation UIApplication (EventReplay)

///
/// - replayEventsFromFile:
///
- (void)replayEventsFromFile:(NSString *)filename 
{
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
  NSString *filePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:filename];
  NSArray* eventList = [[NSArray arrayWithContentsOfFile:filePath] retain];
  [self replayEvents:eventList];
}

///
/// - replayEvents:
///
- (void)replayEvents:(NSArray *)events
{
  if (!events.count)
    return;

  NSDictionary *eventDict = [events objectAtIndex:0U];
  GSEventRef thisEvent = GSEventCreateWithPlist((CFDictionaryRef)eventDict);

  uint64_t eventTime = thisEvent->record.timestamp;
  thisEvent->record.timestamp = mach_absolute_time();

  mach_port_t appPort = GSCopyPurpleNamedPort([[[NSBundle mainBundle] bundleIdentifier] UTF8String]);
  GSSendEvent(&thisEvent->record, appPort);
  mach_port_deallocate(mach_task_self(), appPort); 

  if (events.count <= 1)
    return;

  NSIndexSet *remainderIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(1, events.count - 1)];
  NSArray *remainingEvents = [events objectsAtIndexes:remainderIndexes];

  GSEventRef nextEvent = GSEventCreateWithPlist((CFDictionaryRef)[remainingEvents objectAtIndex:0U]);
  NSTimeInterval nextEventDelay = GetTimeDelta(nextEvent->record.timestamp, eventTime);

  if (nextEventDelay > 0.05)
    [self performSelector:@selector(replayEvents:) withObject:remainingEvents afterDelay:nextEventDelay];
  else
    [self replayEvents:remainingEvents];

  CFRelease(nextEvent);
  CFRelease(thisEvent);
}

@end

上記のスニペットは、イベントを再生する方法を示しています。私の実装はかなり粗雑です。次のイベントをスケジュールするためにやみくもにタイマーを使用すると、遅延が小さすぎると発生しないことがあります。あなたが見る恐ろしいハックは物事をうまく動かしているようです

とにかく、これが何らかの形で他の誰かに役立つことを願っています。

于 2011-02-16T06:40:22.060 に答える