由 testInvocations 动态生成的 XCTest 方法是否可以与 xcodebuild 的 -only-testing 一起使用?

问题描述 投票:0回答:1

我有一个应用程序需要在其

XCTestCase
子类中动态生成测试方法。我使用
+(NSArray<NSInvocation*>*)testInvocations
在运行时动态生成具有以下(虚拟)名称的测试方法:
example_test
permissions_location_test
permissions_many_test
。下面是一个简化的、可直接粘贴到 Xcode 中的代码。

@import XCTest;
@import ObjectiveC.runtime;

@interface ParametrizedTests : XCTestCase
@end

@implementation ParametrizedTests
+ (NSArray<NSInvocation *> *)testInvocations {
  NSLog(@"testInvocations() called");

  /* Prepare dummy input */
  __block NSMutableArray<NSString *> *dartTestFiles = [[NSMutableArray alloc] init];
  [dartTestFiles addObject:@"example_test"];
  [dartTestFiles addObject:@"permissions_location_test"];
  [dartTestFiles addObject:@"permissions_many_test"];

  NSMutableArray<NSInvocation *> *invocations = [[NSMutableArray alloc] init];

  NSLog(@"Before the loop, %lu elements in the array", (unsigned long)dartTestFiles.count);

  for (int i = 0; i < dartTestFiles.count; i++) {
    /* Step 1 */

    NSString *name = dartTestFiles[i];

    void (^anonymousFunc)(ParametrizedTests *) = ^(ParametrizedTests *instance) {
      NSLog(@"anonymousFunc called!");
    };

    IMP implementation = imp_implementationWithBlock(anonymousFunc);
    NSString *selectorStr = [NSString stringWithFormat:@"%@", name];
    SEL selector = NSSelectorFromString(selectorStr);
    class_addMethod(self, selector, implementation, "v@:");

    /* Step 2 */

    NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.selector = selector;

    NSLog(@"RunnerUITests.testInvocations(): selectorStr = %@", selectorStr);

    [invocations addObject:invocation];
  }

  NSLog(@"After the loop");

  return invocations;
}

@end

我可以使用以下方法立即运行所有这些测试:

xcodebuild test \
  -scheme Landmarks \
  -destination 'platform=iOS Simulator,name=iPhone 15'

摘自上述命令的标准输出:

Test Suite 'Selected tests' passed at 2023-11-16 13:44:59.148.
     Executed 3 tests, with 0 failures (0 unexpected) in 0.246 (0.248) seconds

问题

我现在面临的问题是,我无法仅选择一个测试来使用

xcodebuild
-only-testing
标志运行。例如:

xcodebuild test \
  -scheme Landmarks \
  -destination 'platform=iOS Simulator,name=iPhone 15' \
  -only-testing 'LandmarksUITests/ParametrizedTests/example_test'

不起作用 - 未执行任何测试:

Test Suite 'ParametrizedTests' passed at 2023-11-16 13:45:58.472.
     Executed 0 tests, with 0 failures (0 unexpected) in 0.000 (0.000) seconds

我也尝试过这样做:

xcodebuild test \
  -scheme Landmarks \
  -destination 'platform=iOS Simulator,name=iPhone 15' \
  -only-testing 'LandmarksUITests/ParametrizedTests/testInvocations'

但结果是一样的。

所以问题是:如何使用 -only-testing 选项选择测试子集(在运行时使用 testInvocations 动态生成)?。有可能吗?

ios objective-c xctest xcuitest
1个回答
0
投票

经过一番挖掘,我发现当

-only-testing MyTarget/MyClass/myTest
通过时,XCTest 调用测试的方式不同。

我的

LandmarksTests
类缺少对NSObject.instancesRespondToSelector:aSelector:的覆盖。

 @implementation ParametrizedTests
 
+ + (BOOL)instancesRespondToSelector:(SEL)aSelector {
+  [self defaultTestSuite]; // calls testInvocations
+  BOOL result = [super instancesRespondToSelector:aSelector];
+  return true;
+ }
 
 + (NSArray<NSInvocation *> *)testInvocations {
   NSLog(@"testInvocations() called");

这是最终的文件,可以复制粘贴到

ParametrizedTests.m
UI 测试目标内的文件
LandmarksUITests
中,并且工作正常!

@import XCTest;
@import ObjectiveC.runtime;

@interface ParametrizedTests : XCTestCase
@end

@implementation ParametrizedTests

+ (BOOL)instancesRespondToSelector:(SEL)aSelector {
  [self defaultTestSuite]; // calls testInvocations
  BOOL result = [super instancesRespondToSelector:aSelector];
  return true;
}

+ (NSArray<NSInvocation *> *)testInvocations {
  NSLog(@"testInvocations() called");

  /* Prepare dummy input */
  __block NSMutableArray<NSString *> *dartTestFiles = [[NSMutableArray alloc] init];
  [dartTestFiles addObject:@"example_test"];
  [dartTestFiles addObject:@"permissions_location_test"];
  [dartTestFiles addObject:@"permissions_many_test"];

  NSMutableArray<NSInvocation *> *invocations = [[NSMutableArray alloc] init];

  NSLog(@"Before the loop, %lu elements in the array", (unsigned long)dartTestFiles.count);

  for (int i = 0; i < dartTestFiles.count; i++) {
    /* Step 1 */

    NSString *name = dartTestFiles[i];

    void (^anonymousFunc)(ParametrizedTests *) = ^(ParametrizedTests *instance) {
      NSLog(@"anonymousFunc called!");
    };

    IMP implementation = imp_implementationWithBlock(anonymousFunc);
    NSString *selectorStr = [NSString stringWithFormat:@"%@", name];
    SEL selector = NSSelectorFromString(selectorStr);
    class_addMethod(self, selector, implementation, "v@:");

    /* Step 2 */

    NSMethodSignature *signature = [self instanceMethodSignatureForSelector:selector];
    NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:signature];
    invocation.selector = selector;

    NSLog(@"RunnerUITests.testInvocations(): selectorStr = %@", selectorStr);

    [invocations addObject:invocation];
  }

  NSLog(@"After the loop");

  return invocations;
}

@end

另请参阅:

© www.soinside.com 2019 - 2024. All rights reserved.