قالب وردپرس درنا توس
Home / IOS Development / XCTKVOExpectation for Native Swift Key Lanes – Ole Begemann

XCTKVOExpectation for Native Swift Key Lanes – Ole Begemann



The XCTest frame comes with XCTKVOExpectation a nice convenience API to set up an Expectation Based on Cocoa Key Value Observation (KVO).

Using XCTKVOExpectation in Swift is a little less practical than it may be because it does not support original Swift key lanes (yet?). This is not a big deal since the class hides most of the ugly KVO setup code from you, but the additional protection against the type of errors or styles will still be nice to have.

So I wrote a new class, KVOExpectation it does just that. It takes an object and a Swift key path to observe and either an expected value to compare the observed property against or a handling block that allows you to customize when to meet the expectation.

You can use KVOExpectation ] in a test like this:

  func    testLongOperationFinishes   ()    {
      la    on    = [1
9659012]
// ] e = KVOExpectation [19659000]] is Finished expectedValue : sant ) [19659000] la queue = OperationQueue () queue addOperation ( on ) wait ( to . ] timeout [19659007] 5 ) XCTAssertFalse ( on . isCancelled ) [19659058]}

In this example we set an expectation like o bserver a operation s isFinished value. The test claims that the operation is completed successfully.

Note that because the Swift keycourses are heavily written, the compiler can enforce the correct type for the expectedValue parameter – this would not be possible with cocoa key paths.

Deployment depends on the type of Secure Observation API for Swift Key Lanes that Apple added last year when Swift 4.0 was introduced. If you do not use this yet, you should definitely – it's so much nicer to use than the old Objective-C API. I would go so far as to say that it makes KVO a viable data retrieval option, while I would never use the old API voluntarily.

I also wanted to provide convenience methods on XCTestCase for the new expectation type. If you call a method like expectation (description :) in a test, expectation expects automatically with the current test – you do not need to save the return value. A single call to waitForExpectations (timeout: trades :) will then wait for all registered expectations to meet.

Support for this was harder than I expected because XCTestCase Do not provide an API to record custom expectations. I helped myself by registering a dummy expectation with the test case.

This is the current code:

  extension    XCTestCase    {
      @discardableResult 
      func    keyValueObservingExpectation  <  Object :    NSObject        [19659000] 
          to    objectToObserve :    Object [19659007]    keyway :    keyway  <19659012]   Object     Value >  
         alternatives :    NSKeyValueObservingOptions    =    [] 
        :   :    StaticString    =    #fil     line :    Int [19659011] =    #line   ]
         Handling :    ((  Object     NSKeyValueObservedChange  <  Value > [19659007])    ->    Boolean [19659011]]    =    nil ) 
          -?>    XCTestExpectation 
     {
          la    omvik    =    Expectation   ([19659022] :    :         (
              forObject .    objectToObserve     Key Lane :        ] line :    line )) 
          // Following XCTest precedent, which sets `assertForOverFulfill` true by default 
          // for expectations created with` XCTestCase` convenience methods. 
          wrapper .   assertForOverFulfill    =    true 
          // KVO trades in KVOExpectation retains its overall object while observation is active. 
          // That's why we can get away with not keeping KVOExpectation here.   ]    =    KVOExpectation   ([1965902] 2] object :    objectToObserve     keyway :    keyway  
              ] :    alternatives )       [  item     change )    in 
              la    isFulfilled  19659011] =    handles    ==    nil    ||    handles ?   object     change )    ==    true 
              if    isFulfilled    {
                  omvik . 
             
             
                  return 
                  return 
             
            }    otherwise    {
                  return    false 
            }   19659023] wrapper 
    } 
} 

Since it is not possible to keep childbearing expectations retained by the dummy expectation object (without using any associated objects) I trust that the innermost KVO trades refer strongly to the expected object while The observation is active.

Here is an example of user-friendly API that is in use:

  keyValueObservingExpectation   (  for :    on  
    
          keyPath :    ]      expectedValue :    true ) 
  // ... 
  ] waitForExpectations   ( ] timeout :    5 ) 

The full code, including fairly comprehensive device tests, is available as Gist on GitHub. Paste it into a playground to run the device test or gladly include it in your own projects.


Source link