Code Monkey home page Code Monkey logo

combineexpectations's People

Contributors

chris-araman avatar chrisballinger avatar groue avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

combineexpectations's Issues

Cannot find 'XCTFail' in scope (Xcode 12.5)

I believe this is caused by a change in Xcode 12.5: https://developer.apple.com/documentation/Xcode-Release-Notes/xcode-12_5-release-notes/

Xcode no longer includes XCTest’s legacy Swift overlay library (libswiftXCTest.dylib). Use the library’s replacement, libXCTestSwiftSupport.dylib, instead. For frameworks that encounter build issues because of the removal of the legacy library, delete the framework and library search paths for libswiftXCTest.dylib and add the ENABLE_TESTING_SEARCH_PATHS=YES build setting. This setting automatically sets the target’s search paths so that it can locate the replacement XCTest library. (70365050)

I think resolving this may involve a minor podspec change to add the ENABLE_TESTING_SEARCH_PATHS=YES build setting, but I have not verified this yet. If that's the fix, I'm not sure if there's an equivalent fix available for Package.swift and SPM integrations.

Expect recorder to not emit a value

I'm trying to figure out the best way to cover a scenario where I expect a publisher to not to emit a value.

This does not work work because the internal XCTest expectation will mark the test as failed

receivedMessage = try? QuickSpec.current.wait(for: recorder.next(), timeout: 0.1)

The best solution I've found so far is to wrap the line in XCTExpectFailure as following

XCTExpectFailure("this should time out", options: XCTExpectedFailure.Options()) {
    receivedMessage = try? QuickSpec.current.wait(for: recorder.next(), timeout: 0.1)
 }

It still creates this gray "warning" I'd ideally like to get rid of, but I can live with it.
Screenshot 2022-03-01 at 14 44 21

Any opinions on this?

Recorder does not receive elements emitted by a Realm FrozenCollection publisher

I'm tinkering with persistence middleware for an app which uses Redux-like architecture using Realm as a backend. Results from queries on, or changes to the database are emitted by a Combine Publisher.

Although Realm now supports Combine and provides FrozenCollection types to manage threading and concurrency-related errors, I've been advised to use DTOs (structs) to make things as predictable as possible. I've written a test which utilises CombineExpectations to ensure that the conversion of the Realm FrozenCollection to the DTO behaves as expected but the Recorder doesn't receive any elements within the time frame set (1 second). I wondered initially if this was due to the use of .receive(on: DispatchQueue.main) in my operator chain but commenting this out didn't resolve the issue.

Using a "vanilla" Expectation, things works as expected and I've inspected the Publisher using print() (6 elements emitted in total, conversion to DTO working OK) so am working on the assumption that I am missing something although I guess there is the outside possibility there's a glitch somewhere as this is effectively an integration test...?

Currently using Xcode12, iOS14. Code as follows:

Middleware (system under test)

private var cancellables = Set<AnyCancellable>()
 private var subject = CurrentValueSubject<[ToDo.DTO], Never>([])
 
 func allToDos(in realm: Realm = try! Realm()) -> AnyPublisher<[ToDo.DTO], Never> {
     realm.objects(ToDo.self)
         .collectionPublisher
//            .print()
         .assertNoFailure()
         .freeze()
         .map { item in
             item.map { $0.convertToDTO() }
         }
//            .print()
//            .receive(on: DispatchQueue.main)
         .subscribe(subject) // using a Subject to facilitate pipeline sharing and buffering of last output
         .store(in: &cancellables)
         
     return subject.eraseToAnyPublisher()

 }
 
 
 deinit {
     cancellables = []
 }
}

Test class

class SwiftRex_ToDo_PersistedTests: XCTestCase {
    private var realm: Realm?
    
    private var testSet1: [ToDo] {
        [
            ToDo(name: "Mow lawn"),
            ToDo(name: "Wash car"),
            ToDo(name: "Clean windows")
        ]
    }
    
    private var testSet2: [ToDo] {
        [
            ToDo(name: "Walk dog"),
            ToDo(name: "Cook dinner"),
            ToDo(name: "Pay bills")
        ]
    }
    
    override func setUp()  {
        // Put setup code here. This method is called before the invocation of each test method in the class.
        realm = try! Realm(configuration: Realm.Configuration(inMemoryIdentifier: UUID().uuidString))
    }
    
    override func tearDown()  {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
        realm = nil
    }
    
    func testCorrectNumberOfObjectsStoredInRealm() {
        realm!.addForTesting(objects: testSet1)
        XCTAssertEqual(realm!.objects(ToDo.self).count, 3)
        
        realm!.addForTesting(objects: testSet2)
        XCTAssertEqual(realm!.objects(ToDo.self).count, 6)
    }
    
    func testMiddlewarePublisherUsingCombineExpectationsFramework() {
        let sut = PersistenceMiddleware().allToDos(in: realm!)
        let recorder = sut.record()
        
        realm!.addForTesting(objects: testSet1)
        realm!.addForTesting(objects: testSet2)
        
        var elements = [ToDo.DTO]()
        do {
            elements = try wait(for: recorder.prefix(2), timeout: 1).flatMap { $0 }
        } catch {
            XCTFail("Operation failed with error \(error)")
        }
        XCTAssertEqual(elements.count, 6, "Expected 6 elements, received \(elements.count)")
    }
    
    func testMiddlewarePublisherUsingExpectation() {
        let middleware = PersistenceMiddleware()
        var cancellables = Set<AnyCancellable>()
        let receivedValues = expectation(description: "received expected number of published objects")
        
        middleware.allToDos(in: realm!)
            .sink { result in
                if result.count == 6 {
                    NSLog(result.debugDescription)
                    receivedValues.fulfill()
                }
            }
            .store(in: &cancellables)
        
        realm!.addForTesting(objects: testSet1)
        realm!.addForTesting(objects: testSet2)
        
        waitForExpectations(timeout: 1, handler: nil)
    }
    
}

Test output (test using CombineExpectations fails - other tests pass)

Test Suite 'All tests' started at 2020-10-04 13:23:16.699
Test Suite 'SwiftRex-ToDo-PersistedTests.xctest' started at 2020-10-04 13:23:16.700
Test Suite 'SwiftRex_ToDo_PersistedTests' started at 2020-10-04 13:23:16.700
Test Case '-[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testCorrectNumberOfObjectsStoredInRealm]' started.
Test Case '-[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testCorrectNumberOfObjectsStoredInRealm]' passed (0.060 seconds).
Test Case '-[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testMiddlewarePublisherUsingCombineExpectationsFramework]' started.
2020-10-04 13:23:16.790733+0100 SwiftRex-ToDo-Persisted[24035:1350643] [] nw_protocol_get_quic_image_block_invoke dlopen libquic failed
/Users/adrianward/Documents/Xcode/SwiftRex-ToDo-Persisted/SwiftRex-ToDo-PersistedTests/SwiftRex_ToDo_PersistedTests.swift:62: error: -[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testMiddlewarePublisherUsingCombineExpectationsFramework] : Asynchronous wait failed: Exceeded timeout of 1 seconds, with unfulfilled expectations: "".
/Users/adrianward/Documents/Xcode/SwiftRex-ToDo-Persisted/SwiftRex-ToDo-PersistedTests/SwiftRex_ToDo_PersistedTests.swift:66: error: -[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testMiddlewarePublisherUsingCombineExpectationsFramework] : XCTAssertEqual failed: ("0") is not equal to ("6") - Expected 6 elements, received 0
Test Case '-[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testMiddlewarePublisherUsingCombineExpectationsFramework]' failed (1.048 seconds).
Test Case '-[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testMiddlewarePublisherUsingExpectation]' started.
2020-10-04 13:23:17.814079+0100 SwiftRex-ToDo-Persisted[24035:1350455] [SwiftRex_ToDo_Persisted.ToDo.DTO(id: 0, name: "Mow lawn"), SwiftRex_ToDo_Persisted.ToDo.DTO(id: 1, name: "Wash car"), SwiftRex_ToDo_Persisted.ToDo.DTO(id: 2, name: "Clean windows"), SwiftRex_ToDo_Persisted.ToDo.DTO(id: 3, name: "Walk dog"), SwiftRex_ToDo_Persisted.ToDo.DTO(id: 4, name: "Cook dinner"), SwiftRex_ToDo_Persisted.ToDo.DTO(id: 5, name: "Pay bills")]
Test Case '-[SwiftRex_ToDo_PersistedTests.SwiftRex_ToDo_PersistedTests testMiddlewarePublisherUsingExpectation]' passed (0.006 seconds).
Test Suite 'SwiftRex_ToDo_PersistedTests' failed at 2020-10-04 13:23:17.815.
Executed 3 tests, with 2 failures (0 unexpected) in 1.114 (1.116) seconds
Test Suite 'SwiftRex-ToDo-PersistedTests.xctest' failed at 2020-10-04 13:23:17.816.
Executed 3 tests, with 2 failures (0 unexpected) in 1.114 (1.116) seconds
Test Suite 'All tests' failed at 2020-10-04 13:23:17.816.
Executed 3 tests, with 2 failures (0 unexpected) in 1.114 (1.117) seconds

Carthage support? :)

Hey! This project looks very nice indeed! Im the OP of the Swift Forum thread you recently announced this project in.

I'm of course keen on using SPM, but unfortunately one of my dependencies BitcoinKit does not yet support SPM, so for now I'm stuck in Carthage land.

In a fork of this project I'm trying adding a shared scheme, to a swift package generate-xcodeproj generated project, but when I try using this fork, carthage fails to build, due to XCTest:

ld: warning: Could not find or use auto-linked framework 'XCTest'
Undefined symbols for architecture arm64:
  "_OBJC_CLASS_$_XCTestExpectation", referenced from:
      objc-class-ref in PublisherExpectation.o
      objc-class-ref in Recorder.o
ld: symbol(s) not found for architecture arm64

Any clues on how to fix it?

Use @discardableResult

It would be great if the wait(...) functions would be annotated with @discardableResult, removing the need for _ = in _ = try wait(for:timeout:)

wait is causing in a quick test "Implicit use of 'self' in closure; use 'self.' to make capture semantics explicit"

Hey, I'm new to Swift, and trying to use this library. I've got a method that I'm trying to test on my repo class:

func createActivity(name: String, uuid: UUID) -> AnyPublisher<Activity.ApiProxy, ApiError> {

in the tests I've got

it("fetches activities") {
                let repo = RepoMan(email: "[email protected]", password: "password", moc: PersistenceController.preview.container.viewContext)

                let uname = "Hey Girl \(NSDate().timeIntervalSince1970)"
                let uuid = UUID()

                let activityPub = repo.createActivity(name: uname, uuid: uuid)
                let recorder = activityPub.record()
                let elements = try wait(for: recorder.elements, timeout: 3.0)
         // assertions on elements here

the wait line triggers the error

Implicit use of 'self' in closure; use 'self.' to make capture semantics explicit

I couldn't figure out what was going on, I realized that the closure context it might be referring to is the Quick test context it() {}

but I figured it doesn't hurt to ask in case you have a quick fix.

Thanks for the library and for taking your time to read this!

Expectation that returns the set of elements without requiring completion

I think there's a gap in the API for when you're dealing with publishers that will never complete. What I'm looking for is a combination between elements and next(_): An expectation that will simply return whatever elements have been recorded by the time the timeout completes.

elements won't work because it requires the publisher to complete. next(_) won't work because it requires you to provide a number of elements to wait for, but if the code under test isn't behaving as expected then there may be more elements that you're missing.

The workaround that I have right now is to use prefix(_).inverted with some arbitrary high number like 100. The problem there is (a) I have to provide a number, and (b) the elements aren't consumed. Calling prefix() multiple times will include elements that were already returned before.

Using share() on publishers results in recorder to return nil

Summary

Not sure if it's expected but running some tests, and whenever I'm using the share() operator, I get failing tests for the expected recorded result. Removing the operator fixes the test, but now I am no longer sharing the upstream result of the publisher.

Example

// function being tested
let publisher = "hello".publisher.share()

publisher
.sink { ... } 

publisher.
 .sink { ... } 

// Test
let recorder = publisher.prefix(1).record()

let value = try wait(recorder.single, timeout: 0.3) // value is nil

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.