在 Xcode 中通过 Objective-C 代码测试 Swift 代码

Posted

技术标签:

【中文标题】在 Xcode 中通过 Objective-C 代码测试 Swift 代码【英文标题】:Testing Swift code through Objective-C code in Xcode 【发布时间】:2016-07-19 13:43:25 【问题描述】:

我正在为我的项目编写测试用例 (XCTestCases),其中混合了 Obj-C 和 Swift 代码。 我能够用 swift 语言为 Objective C 代码编写测试用例。 但我无法访问 Objective C 测试文件中的 swift 类。它显示编译器错误。

    我在我的 Objective C 测试文件中导入了#import "MyProjectTests-Swift.h" 文件。 测试目标的“启用可测试性”和“定义模块”设置为“是”

我错过了什么吗?当我打开“MyProjectTests-Swift.h”文件时,我看不到 Obj C 为 Swift 代码生成的声明。

我的代码

#import <XCTest/XCTest.h>
#import <OCMock/OCMock.h>
#import "MyProjectTests-Swift.h"


- (void)testExample     
   MyController *myController= [[MyController alloc] init];

错误

1. Use of undeclared identifier 'MyController'
2. Use of undeclared identifier 'myController'

MyProjectTests-Swift.h 代码

// Generated by Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31)
#pragma clang diagnostic push

#if defined(__has_include) && __has_include(<swift/objc-prologue.h>)
# include <swift/objc-prologue.h>
#endif

#pragma clang diagnostic ignored "-Wauto-import"
#include <objc/NSObject.h>
#include <stdint.h>
#include <stddef.h>
#include <stdbool.h>

#if !defined(SWIFT_TYPEDEFS)
# define SWIFT_TYPEDEFS 1
# if defined(__has_include) && __has_include(<uchar.h>)
#  include <uchar.h>
# elif !defined(__cplusplus) || __cplusplus < 201103L
typedef uint_least16_t char16_t;
typedef uint_least32_t char32_t;
# endif
typedef float swift_float2  __attribute__((__ext_vector_type__(2)));
typedef float swift_float3  __attribute__((__ext_vector_type__(3)));
typedef float swift_float4  __attribute__((__ext_vector_type__(4)));
typedef double swift_double2  __attribute__((__ext_vector_type__(2)));
typedef double swift_double3  __attribute__((__ext_vector_type__(3)));
typedef double swift_double4  __attribute__((__ext_vector_type__(4)));
typedef int swift_int2  __attribute__((__ext_vector_type__(2)));
typedef int swift_int3  __attribute__((__ext_vector_type__(3)));
typedef int swift_int4  __attribute__((__ext_vector_type__(4)));
#endif

#if !defined(SWIFT_PASTE)
# define SWIFT_PASTE_HELPER(x, y) x##y
# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y)
#endif
#if !defined(SWIFT_METATYPE)
# define SWIFT_METATYPE(X) Class
#endif

#if defined(__has_attribute) && __has_attribute(objc_runtime_name)
# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X)))
#else
# define SWIFT_RUNTIME_NAME(X)
#endif
#if defined(__has_attribute) && __has_attribute(swift_name)
# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X)))
#else
# define SWIFT_COMPILE_NAME(X)
#endif
#if !defined(SWIFT_CLASS_EXTRA)
# define SWIFT_CLASS_EXTRA
#endif
#if !defined(SWIFT_PROTOCOL_EXTRA)
# define SWIFT_PROTOCOL_EXTRA
#endif
#if !defined(SWIFT_ENUM_EXTRA)
# define SWIFT_ENUM_EXTRA
#endif
#if !defined(SWIFT_CLASS)
# if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted)
#  define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA
#  define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# else
#  define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
#  define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA
# endif
#endif

#if !defined(SWIFT_PROTOCOL)
# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA
#endif

#if !defined(SWIFT_EXTENSION)
# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__)
#endif

#if !defined(OBJC_DESIGNATED_INITIALIZER)
# if defined(__has_attribute) && __has_attribute(objc_designated_initializer)
#  define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
# else
#  define OBJC_DESIGNATED_INITIALIZER
# endif
#endif
#if !defined(SWIFT_ENUM)
# define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type
# if defined(__has_feature) && __has_feature(generalized_swift_name)
#  define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type
# else
#  define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name)
# endif
#endif
#if defined(__has_feature) && __has_feature(modules)
#endif

#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch"
#pragma clang diagnostic ignored "-Wduplicate-method-arg"
#pragma clang diagnostic pop

MyController Swift 类

import Foundation

class MyController: UIViewController, UITextFieldDelegate 

// Project specific logic


【问题讨论】:

错误是什么?你用的是什么代码? @LucaD'Alberti,我添加了代码。正如我提到的,我无法访问 Obj C 文件中的 Swift 类。 MyProjectTests-Swift.h 里面有什么? @LucaD'Alberti 已添加.....我猜它应该有“MyController”类的Objective C声明,但它丢失了 【参考方案1】:

我遇到了问题。测试目标中缺少桥接头(Swift 编译器 - 代码生成 - > Objective-C 桥接头) 我刚刚添加了它并构建了项目。现在 MyProjectTests-Swift.h 显示了所有客观的 C 生成的标头声明。

如果有人遇到同样的问题,希望这会有所帮助。

【讨论】:

我想知道为什么这是一个问题。您的桥接头是否有一个特殊的名称,而不是 ProjectName-Bridging-Header.h?【参考方案2】:

发现这个问题正在寻找一个相关的问题,为此我需要做一些其他事情来解决它:当您的应用程序使用 Swift 和 Objective-C,并且您的测试目标也有混合语言时,那么您将想要编写这个在你的测试文件中访问你的 ObjC 测试中的 Swift 类型:

#import "AppName-Swift.h"

如果这对您不起作用,那可能是因为测试目标无法找到应用目标生成的标头开箱即用。

解决方案

添加

$CONFIGURATION_TEMP_DIR/AppName.build/DerivedSources

到您的测试目标的构建设置>标题搜索路径。然后您的测试将能够找到应用生成的标头。

【讨论】:

以上是关于在 Xcode 中通过 Objective-C 代码测试 Swift 代码的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Objective-C 中通过 JSON 发布 REST

测试在 Xcode 中通过,但在 Circleci 上失败

如何在 Xcode 中通过代码触发按钮

在xcode中通过sqlite3检查存在

在Xcode 8中通过一些错误运行项目后[重复]

在 Xcode 11 中通过 Fastlane 构建 SPM 包不起作用