diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme index 3df8b77a24..9b2979aa71 100644 --- a/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme +++ b/.swiftpm/xcode/xcshareddata/xcschemes/Firebase-Package.xcscheme @@ -734,6 +734,104 @@ ReferencedContainer = "container:"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/FirebaseFirestoreTestingSupport.podspec b/FirebaseFirestoreTestingSupport.podspec new file mode 100644 index 0000000000..452a6cf9b5 --- /dev/null +++ b/FirebaseFirestoreTestingSupport.podspec @@ -0,0 +1,58 @@ +Pod::Spec.new do |s| + s.name = 'FirebaseFirestoreTestingSupport' + s.version = '1.0.0' + s.summary = 'Firebase SDKs testing support types and utilities.' + + s.description = <<-DESC + Type declarations and utilities needed for unit testing of the code dependent on Firebase SDKs + DESC + + s.homepage = 'https://developers.google.com/' + s.license = { :type => 'Apache', :file => 'LICENSE' } + s.authors = 'Google, Inc.' + + s.source = { + :git => 'https://github.com/Firebase/firebase-ios-sdk.git', + :tag => 'CocoaPods-' + s.version.to_s + } + + ios_deployment_target = '10.0' + osx_deployment_target = '10.12' + tvos_deployment_target = '10.0' + watchos_deployment_target = '6.0' + + s.ios.deployment_target = ios_deployment_target + s.osx.deployment_target = osx_deployment_target + s.tvos.deployment_target = tvos_deployment_target + s.watchos.deployment_target = watchos_deployment_target + + s.cocoapods_version = '>= 1.4.0' + s.prefix_header_file = false + s.requires_arc = true + + base_dir = 'FirebaseTestingSupport/Firestore/' + + s.source_files = [ + base_dir + 'Sources/**/*.{m,mm,h}', + 'Firestore/Source/API/*\+Internal.h' + ] + + s.public_header_files = base_dir + '**/*.h' + + s.dependency 'FirebaseFirestore', '~> 7.7' + + s.pod_target_xcconfig = { + 'GCC_C_LANGUAGE_STANDARD' => 'c99', + 'OTHER_CFLAGS' => '-fno-autolink', + 'HEADER_SEARCH_PATHS' => + '"${PODS_TARGET_SRCROOT}" ' + } + + s.test_spec 'unit' do |unit_tests| + unit_tests.scheme = { :code_coverage => true } + unit_tests.platforms = {:ios => ios_deployment_target, :osx => osx_deployment_target, :tvos => tvos_deployment_target} + unit_tests.source_files = [ + base_dir + 'Tests/**/*.swift' + ] + end +end diff --git a/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm b/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm new file mode 100644 index 0000000000..cf100a2742 --- /dev/null +++ b/FirebaseTestingSupport/Firestore/Sources/FIRQueryFake.mm @@ -0,0 +1,32 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import "FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h" + +#import "Firestore/Source/API/FIRQuery+Internal.h" + +@implementation FIRQueryFake + +- (instancetype)init { + // The object is partially initialized. Make sure the methods used during testing are overridden. + return self; +} + +- (void)getDocumentsWithCompletion:(FIRQuerySnapshotBlock)completion { + if (self.getDocumentsHandler) { + self.getDocumentsHandler(completion); + } +} + +@end diff --git a/FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h b/FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h new file mode 100644 index 0000000000..f7db2c7ee0 --- /dev/null +++ b/FirebaseTestingSupport/Firestore/Sources/Public/FirebaseFirestoreTestingSupport/FIRQueryFake.h @@ -0,0 +1,34 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#import + +NS_ASSUME_NONNULL_BEGIN + +typedef void (^FIRFirestoreGetDocumentsHandler)(FIRQuerySnapshotBlock completion); + +/// A fake object to replace a real `Query` in tests. +NS_SWIFT_NAME(QueryFake) +@interface FIRQueryFake : FIRQuery + +- (instancetype)init; + +/// The block to be called each time when `getDocuments(completion:)` method is called. +@property(nonatomic, nullable, copy) FIRFirestoreGetDocumentsHandler getDocumentsHandler; + +// TODO: Implement other handlers as needed. + +@end + +NS_ASSUME_NONNULL_END diff --git a/FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift b/FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift new file mode 100644 index 0000000000..647d85ae13 --- /dev/null +++ b/FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift @@ -0,0 +1,44 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import XCTest +@testable import FirebaseFirestoreTestingSupport + +class QueryFakeTests: XCTestCase { + func testQueryFakeConstructor() throws { + let fakeQuery = QueryFake() + XCTAssertNotNil(fakeQuery) + XCTAssertTrue(fakeQuery.isKind(of: Query.self)) + } + + func testQueryFakeGetDocumentsHandler() { + let fakeQuery = QueryFake() + + let handlerExpectation = expectation(description: "Handler called") + fakeQuery.getDocumentsHandler = { completion in + handlerExpectation.fulfill() + + completion(nil, nil) + } + + let completionExpectation = expectation(description: "Completion called") + fakeQuery.getDocuments { snapshot, error in + completionExpectation.fulfill() + XCTAssertNil(snapshot) + XCTAssertNil(error) + } + + wait(for: [handlerExpectation, completionExpectation], timeout: 0.5) + } +} diff --git a/FirebaseTestingSupport/README.md b/FirebaseTestingSupport/README.md new file mode 100644 index 0000000000..91cf8fc4e5 --- /dev/null +++ b/FirebaseTestingSupport/README.md @@ -0,0 +1,53 @@ +# Firebase Testing Support (for automated test developers) + +Firebase Testing Support is a collection of libraries that provide type definitions and tools required for writing tests for code that uses Firebase, e.g.: + +- Instances of types like `Query` cannot be created with a simple constructor which makes unit testing of the code that depends on them difficult/impossible. Firestore Testing Support lib provides a type `QueryFake` that can be instantiated and used instead of actual `Query` instances in the tests. + +## Usage + +### Add dependency to your test target + +#### Cocoapods + +``` +tests.dependency 'FirebaseFirestoreTestingSupport', '~> 1.0' +``` + +#### Swift Package Manager + +``` +dependencies: [ + ... + "FirebaseFirestoreTestingSupport" +], + +``` + +### Use the fake types in the tests instead of real types + +See test for example, e.g. [QueryFakeTests.swift](../FirebaseTestingSupport/Firestore/Tests/QueryFakeTests.swift). + +## Development + +### Generate project + +#### Cocoapods + +E.g. for `FirebaseFirestoreTestingSupport` run the following command for the root repo directory: + +``` +pod gen --auto-open --local-sources=./ FirebaseFirestoreTestingSupport.podspec --platforms=ios +``` + +#### Swift Package Manager + +- Open the main package definition: + +``` +xed Package.swift +``` + +- Select (or add if not exists yet) a scheme for the test target, e.g. `FirestoreTestingSupportTests` + +- make required modifications and run tests as needed. \ No newline at end of file diff --git a/Package.swift b/Package.swift index 489a826bc7..c1619eb714 100644 --- a/Package.swift +++ b/Package.swift @@ -837,6 +837,28 @@ let package = Package( .define("FIR_VERSION", to: firebaseVersion), ] ), + + // MARK: Testing support + + .target( + name: "FirebaseFirestoreTestingSupport", + dependencies: ["FirebaseFirestore"], + path: "FirebaseTestingSupport/Firestore/Sources", + publicHeadersPath: "./", + cSettings: [ + .headerSearchPath("../../.."), + .headerSearchPath("../../../Firestore/Source/Public/FirebaseFirestore"), + ] + ), + .testTarget( + name: "FirestoreTestingSupportTests", + dependencies: ["FirebaseFirestoreTestingSupport"], + path: "FirebaseTestingSupport/Firestore/Tests", + cSettings: [ + .headerSearchPath("../../.."), + ] + ), + ], cLanguageStandard: .c99, cxxLanguageStandard: CXXLanguageStandard.gnucxx14