quick / nimble Goto Github PK
View Code? Open in Web Editor NEWA Matcher Framework for Swift and Objective-C
Home Page: https://quick.github.io/Nimble/documentation/nimble/
License: Apache License 2.0
A Matcher Framework for Swift and Objective-C
Home Page: https://quick.github.io/Nimble/documentation/nimble/
License: Apache License 2.0
These matchers should match only true
and false
. In short, they alias to equal(true)
and equal(false)
respectively.
See the discussion for details: #95 (comment)
Basically, implementing "meta-matchers" (matchers that are composed from other matchers, like allPass()
and Guanaco's haveSucceeded()
and haveFailed()
is made difficult by the fact that matchers could be one of three distinct, unrelated types: Matcher
, BasicMatcher
, and NonNilBasicMatcher
.
It should be easy to define a function that takes a matcher without defining three signatures, like allPass()
does:
public func allPass<U,V where U: SequenceType, V: NonNilBasicMatcher, U.Generator.Element == V.ValueType>(matcher: V) -> NonNilMatcherFunc<U>
public func allPass<U,V where U: SequenceType, V: BasicMatcher, U.Generator.Element == V.ValueType>(matcher: V) -> NonNilMatcherFunc<U>
public func allPass<U,V where U: SequenceType, V: Matcher, U.Generator.Element == V.ValueType>(matcher: V) -> NonNilMatcherFunc<U>
In the linked discussion, @jeffh elaborates:
Yeah, there needs to be some changes to simplify the internals. I think the removal of
BasicMatcher
andNonNilBasicMatcher
would be preferred in some way. There also needs a reinvestigation if the Swift compiler still gives an obscure message when a generic does match optionals. Having the matcher be able to specify that while Nimble's expectation and matcher protocols be ignorant of that detail would be best.
For a class
class Tester {
var value = "42"
}
and a declaration
let testObject = Tester()
this test works
expect(testObject === testObject).to(beTruthy())
but this doesn't even compile
expect(testObject).to(beIdenticalTo(testObject))
That's because beIdenticalTo only works with classes inheriting from NSObject, but XCode won't tell you that. It will complain that it cannot find a member "to". For Swift it's pretty useless to have a matcher depend on NSObject as Swift classes normally don't inherit from NSObject. Will anyone inherit from NSObject only to be able to write such a test on it? I'm aware that beIdenticalTo isn't possible in another way. You need some class type as a type constraint to use ===, but there seems to be no way to constraint a generic type parameter to be a class.
And don't try it with Strings. In
let testObject = "42"
expect(testObject === testObject).to(beTruthy())
expect(testObject).to(beIdenticalTo(testObject))
the first test gets a compile error because === isn't available on Strings.
The second one compiles but fails and claims to be comparing two different objects. I guess that somehow the String is converted into some NSObject on each of the two positions.
In my opinion beIdenticalTo does more harm than good and should probably be removed.
Let me know if this sort of thing would be better left as an external custom matcher outside of the Quick org, but I think it'd be nifty to be able to write:
let error = NSError()
expect(error).to(beAnError(
domain: equal("io.modocache.Gift"),
localizedDescription: match("Could not resolve path")
))
Note that I can use matchers for the domain
and localizedDescription
. This is different than how Nimble's NSException
matcher currently works, and is more in line with #96.
I have a fresh install of XCode 6.0.1 and a clone of Nimble from today (last commit: 33b4916)
When I import Nimble into my project according to the README for Quick, the framework appears in red as in the following screenshot. Quick seems to work fine.
In order for Nimble to work with Carthage or CocoaPods, it needs tagged releases.
import Quick
import Nimble
class TSpec: QuickSpec {
override func spec() {
describe("it") {
it("works") {
// let someValue = 0
expect(0) == 0
}
}
}
}
produces the compiler error: Cannot invoke '==' with an argument list of type '(StringLiteralConvertible, () -> () -> $T2)'
As soon as you uncomment the commented line it starts to work. You can also add this line after the expectation or add another expectation like "expect(1) == 1".
To sum it up: It doesn't work if the expectation using an operator is the only content of an it.
Hello!
I have the following code:
let result = ["how":1, "think":1, "didnt":2, "because":1,
"interesting":1, "always":1, "right":1, "such":1,
"to":3, "say":1, "cool":1, "you":1,
"weather":3, "be":1, "went":1, "was":2,
"sometimes":1, "and":3, "mind":1, "rain":1,
"whole":1, "everything":1, "weather.":1, "down":1,
"kind":1, "mood.":1, "it":2, "everyday":1, "might":1,
"more":1, "have":2, "person":1, "could":1, "tenth":2,
"night":1, "write":1, "Youd":1, "affects":1, "of":3,
"Who":1, "us":1, "an":1, "I":4, "my":1, "much":2,
"wrong.":1, "peacefully.":1, "amazing":3, "would":4,
"just":1, "grade.":1, "Its":2, "The":2, "had":1, "that":1,
"the":5, "best":1, "but":1, "essay":1, "for":1, "summer":2,
"your":1, "grade":1, "vary":1, "pretty":1, "at":1, "rain.":1,
"about":1, "allow":1, "thought":1, "in":1, "sleep":1, "a":1,
"hot":1, "really":1, "beach":1, "life.":1, "we":1, "although":1]
let storyCount = ["The":2, "summer":2, "of":3, "tenth":2, "grade":1,
"was":2, "the":5, "best":1, "my":1, "life.":1, "I":4,
"went":1, "to":3, "beach":1, "everyday":1, "and":3,
"we":1, "had":1, "amazing":3, "weather.":1, "weather":3,
"didnt":2, "really":1, "vary":1, "much":2, "always":1,
"pretty":1, "hot":1, "although":1, "sometimes":1, "at":1,
"night":1, "it":2, "would":4, "rain.":1, "mind":1, "rain":1,
"because":1, "cool":1, "everything":1, "down":1, "allow":1,
"us":1, "sleep":1, "peacefully.":1, "Its":2, "how":1,
"affects":1, "your":1, "mood.":1, "Who":1, "have":2,
"thought":1, "that":1, "could":1, "write":1, "a":1,
"whole":1, "essay":1, "just":1, "about":1, "in":1,
"grade.":1, "kind":1, "right":1, "Youd":1, "think":1,
"for":1, "such":1, "an":1, "interesting":1, "person":1,
"might":1, "more":1, "say":1, "but":1, "you":1, "be":1, "wrong.":1]
expect(result).to(equal(storyCount))
And I get a test fail on the expect line! I've ensured that the two dictionaries are equal by putting a break point on the expect line and running result == storyCount
in lldb and receiving true
. Here is what I've done so far to try and debug this:
describe
block and a single it
block. Still failed the expect.let result = ["The":2,"summer":2]
let storyCount = ["The":2, "summer":2]
expect(result).to(equal(storyCount))
Any ideas?
Created the branch new project. Added the following podfile.
source 'https://github.com/CocoaPods/Specs.git'
platform :ios, '8.0'
target "" do
pod 'Quick', :git => 'https://github.com/Quick/Quick', :tag => 'v0.2.2'
pod 'Nimble', :git => "https://github.com/Quick/Nimble"
end
When i compile the app I get the following error.
Pods/Nimble/Nimble/Adapters/AssertionRecorder.swift:44:20: error: use of unresolved identifier 'NMBExceptionCapture'
let capturer = NMBExceptionCapture(handler: nil, finally: ({
Use of unresolved Identifier 'NMBExceptionCapture'. In DSL.m i get the error use of 'Nimble/Nimble-swift.h' file not found for #import <Nimble/Nimble-Swift.h>.
In Swift, contain()
works on containers and strings, but attempting to use it for substrings in Objective-C results in errors like the following:
failed - expected to contain <Optional(foobarfuzzbuzz)>, got <foobarfuzzbuzz>
failed - expected to contain <Optional(barfuzz)>, got <foobarfuzzbuzz>
A client project that was switching to use Nimble encountered this error on Xcode 6.2 final.
This error was resolved by adding #import <Nimble/Nimble-Swift.h>
which includes the swift code. Need to verify if Swift 1.2 also has this issue. Make sure to clean derived data before trying to reproduce this.
Reinvestigate including this import in the umbrella import header.
getting these errors w/ xcode6.3 beta3:
AsyncMatcherWrapper.swift:
AsyncMatcherWrapper.swift:43:35: Extra argument 'timeoutInterval' in call
AsyncMatcherWrapper.swift:57:38: Extra argument 'timeoutInterval' in call
Crosslisted from Quick#70.
This should be working already, but tests definitely need to be added.
Running tests on iPhone 5s and iPad Air simulators work, but other ones seem to fail. See this issue where it has surfaced for context.
This might be a bug to report to Apple.
I'm having problems with raiseException()
in Swift. I expected this test to pass:
it("throws an exception when an index is out of bounds") {
let array = [1,2,3]
expect(array[3]).to(raiseException())
}
Instead, I get a crash because the exception thrown by array[3]
is not caught. Am I missing something? Does raiseException()
only work when a NSException
is thrown and not with calls to fatalError()
, precondition()
etc. (what I assume Swift’s array type is using)?
Edit: I assume this is the intended behavior because Swift has no try/catch support (yet?). For the same reason that XCTAssertThrows()
is not available. Just wanted to mention that from the description of raiseException()
in the readme I expected this to work. Perhaps this caveat can be included in the readme?
Syntax highlighting in the code samples is off; probably a missing paren: https://github.com/Quick/Nimble#asynchronous-expectations
In Jasmine, you can assert that all elements in a collection pass a specified condition:
expect([1, 2, 3]).toAllPass(function (value) {
return value > 0;
});
Of course, you could write an equivalent assertion using Nimble's beTrue()
, but toAllPass
probably has more descriptive failure messages (i.e.: which element caused the assertion to fail).
Thoughts? 🙌
Related to Quick/Quick#132
I was wondering if there was a reason why toEventually
, etc don't use XCTestExpectation
internally via expectationWithDescription
, waitForExpectationsWithTimeout
, and fulfill
.
I think I've followed the simple install instructions correctly, but I'm unable to run any tests (not even the ones that don't use Quick). I get the following error after which my application loads normally. However, the testing never completes:
2014-10-01 13:01:09.821 BatteryPack[2531:906788] Error loading /private/var/mobile/Containers/Data/Application/8E62838C-4A6A-44CA-9B1C-151B1ED11384/tmp/BatteryPackTests.xctest/BatteryPackTests: dlopen(/private/var/mobile/Containers/Data/Application/8E62838C-4A6A-44CA-9B1C-151B1ED11384/tmp/BatteryPackTests.xctest/BatteryPackTests, 262): Library not loaded: @rpath/Quick.framework/Quick
Referenced from: /private/var/mobile/Containers/Data/Application/8E62838C-4A6A-44CA-9B1C-151B1ED11384/tmp/BatteryPackTests.xctest/BatteryPackTests
Reason: image not found
Any idea what is missing?
Currently I can write the following in Objective-C:
// Objective-C
expectAction(
[NSException raise:NSRangeException
format:@"Now you've gone too far!"]
).to(raiseException());
But I can't make an expectation on the name
of the exception, nor the reason
, nor the userInfo
.
In Swift, you can write an expectation that only passes when the name
and reason
match (with userInfo
support coming soon in #12). I think you should be able to do the same in Objective-C.
What should the syntax look like? I like beCloseTo(expected).within(delta)
. How about the following as a first draft?
expectAction(
[NSException raise:NSRangeException
format:@"Now you've gone too far!"]
).to(raiseException().
named(NSRangeException).
withReason(@"Now you've gone too far!").
andUserInfo(@{@"length": @10}));
It seems that Nimble is missing beEmpty
matcher in Objective-C. Is it missing just by accident or is there a technical reason to omit it?
I cloned the latest version from the repo and am not able to get the project to build. I just cloned it, opened the project in XCode 6.1.1 and am trying to build it, but seeing around 38 errors. Haven't done anything else to it. One is in DSL.m, where it references <Nimble/Nimble-Swift.h>, however Nimble-Swift.h doesn't appear to exist anywhere. In addition, there are a lot of places where casting with "expected as! String" is being used and Xcode is complaining that it's expecting a type after "as". In Equal.swift, the class "Set" is being used, however the class does not appear to exist. Perhaps I'm doing something incorrectly because it's showing as build passing on Github.
I am having a heck of a time getting Nimble integrated w/ an iOS project. The issue at the moment seems to be related to
I have tried the workarounds mentioned in the SO link, to no avail. My compiler is still saying
<unknown>:0: error: using bridging headers with framework targets is unsupported
Note: I am using XCode6 beta4 for this.
Is this a known issue?
Example failure messages from Nimble 0.2:
/var/lib/jenkins/workspace/Mac/UnitTests/GHCommitMessageViewModelSpec.m:94: failed - expected to begin with <Conflicts:>, got <Conflicts:README>:
91 waitUntilCompleted:NULL];
92
93 expect(viewModel.commitSummary).withTimeout(5).toEventually(equal(@"Merge branch 'new'"));
94 expect(viewModel.commitDescription).to(beginWith(@"Conflicts:"));
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
95 });
96
PR #99 added support for custom matchers when validating raiseExceptions. This should be updated to some better sentence. A random proposal:
expected to raise an exception with name to equal <foo> with reason to begin with <bar> with userInfo containing <[baz: buzz]>.
But maybe making the error more concise might be better too.
For full discussion, see #78. @MarcoSero writes:
Would you mind dealing with the Cocoapods specs etc. to change mine to Nimble-CoreData? Thank you
/cc @kylef
The previous failure reporting was more concise and better communicated intent. For example, the equal matcher would give expected 'x', got 'y'
. Now it gives expected <x> to equal <y>
. If a matcher expected the test subject not to be nil it would report expected subject not to be nil
. Now it reports a variation on expected <nil> to contain <x>
.
I have some enums and structs that, by an extensions, support printable, but the results always come out as defined in their description methods. The types are generally used in an array.
Xcode 6.1.1
Or just match to true
and false
. The Objective-C variants need to be updated keep the behavior consistent with the Swift implementation..
Aren't these executed out of context of the @try/@catch ...?
I am asking because I tried implementing something very similar in order to be able to extend NSException with a try...catch..finally construct that would allow me to use exceptions in swift.
However, all my tests failed since the closures I passed in would be executed lazily while my ObjectiveC based category would never catch the exceptions being thrown.
Please note that I did not use auto closures...
TIA for enlightening me...
My builds are failing with the above error. I tried it with a couple of projects and even a brand new one with nothing but Nimble and the sample test cases that come with a new project.
Here are my steps in case I'm doing something dumb:
Oddly enough I can run the Nimble tests themselves (in the Nimble project) and not get an error. I can send you the simple test project I created if you need me to.
We recently discovered that tests execution is not quite serial, as it is still possible to have multiple tests executing at same time. Such situations cause waitUntil executing longer than usual. We profiled method done to the _pollBlock function and found that NSRunLoop.mainRunLoop().runUntilDate(runDate) is slow and it depends on availability of waitUntils in parallel tests. Is it known and expected behavior?
Hi,
I am currently trying to utilise Quick, but hitting a brick wall when it comes to installing nimble. At the moment I have just included Nimble to try and isolate the issue. It is currently cloned as a submodule (using the 0.4.0 hash) as I can see on travis that last couple of commits have failed on travis ci - again to try and isolate the issue
Currently I have included the XCodeProj into the Tests (FormularyTests) object within Xcode, but when I try and link the framework with the binary, or when it is being inspected, the build will fail with 224 errors across a lot of the swift files. An example of this can be found here - https://gist.github.com/ssherar/768004cf60fc6671c39e
Have you seen this before and is there anything I can do to resolve this?
Sam
For context: see discussion on #88. Quoting @klaaspieter:
I would like to say that I would prefer consistency for expect.
When writing my tests I don't want to have to think about the choice between {} and (). I also want to safely be able to change expect(value).to(equal(1)) to expect(value).toEventually(equal(1)) without my specs failing for seemingly no reason.
If Swift requires {} for lazily evaluated values, than I would argue {} should be used in all other cases as well.
There is definitely an interesting arguments to be made for both:
expect { ... }
is more consistent for switching between to
and toEventually
matchersexpect(...)
can better describe intent ("This value doesn't need to be lazily evaluated"). Although the previous usage of @autoclosure
negated that.See Quick/Quick#65 for the original idea, and Quick/Quick#68 for a sample implementation using Quick's old matcher infrastructure.
Ideally usage would look something like:
expect("867-5309").to.match("\d{3}-\d{4}")
expect("foo").to(contain("oo"))
gives the compiler error:
Type 'MatcherFunc' does not conform to protocol 'Matcher'
How do I write the following in Objective-C?
// Swift
// Waits three seconds for ocean to contain "starfish":
expect(ocean).toEventually(contain("starfish"), timeout: 3)
Poking around at ObjCMatcher.swift
, it seems like Nimble doesn't support custom timeouts in Objective-C. I think it should. Thoughts?
I can write the following, very convenient, assertion in Swift:
// Swift
expect(["whale", "dolphin", "starfish"]).to(contain("dolphin", "starfish"))
But in Objective-C, I can't pass multiple arguments to contain
, so I have to write two lines:
// Objective-C
expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"dolphin"));
expect(@[@"whale", @"dolphin", @"starfish"]).to(contain(@"starfish"));
It'd be nice if Objective-C contain
supported multiple arguments somehow (the same goes for beginWith
and endWith
).
Currently, waitUntil
is only available in Swift. This task should also update the README, which states that fact as well.
Nimble doesn't compile on Xcode 6.1b2:
<unknown>:0: error: filename "Protocols.swift" used twice: '/Users/modocache/GitHub/modocache/Quick/Externals/Nimble/Nimble/Adapters/Protocols.swift' and '/Users/modocache/GitHub/modocache/Quick/Externals/Nimble/Nimble/Matchers/Protocols.swift'
<unknown>:0: note: filenames are used to distinguish private declarations with the same name
Command /Applications/Xcode-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swiftc failed with exit code 1
Not sure what works and what doesn't on Xcode 6.0 GM.
Moved from Quick/Quick#131:
I'm trying to compare a json object from a server with a local one. Calling equal() with the local dictionary only works if the dictionary is created in the function or casted to a NSDictionary, while casting it to Dictionary fails.
let expectedDict = ["key": "value"]
// fails
expect({return jsonObject}).toEventually(equal(expectedDict as Dictionary<String, String>), timeout: 3)
// works
expect({return jsonObject}).toEventually(equal(expectedDict as NSDictionary), timeout: 3)
expect({return jsonObject}).toEventually(equal(["key": "value"]), timeout: 3)
Hi,
I just started using Quick + Nimble, and I noticed that all my expectations are run even when the first one fails. Is there a way make the test crash after the first failure?
People using Nimble with Swift 1.2 should be able to specify their version without using a SHA directly. See also: Quick/Quick#246
The raiseException()
matcher uses strict equality for the name and reason of an exception:
// Passes if actual raises an exception with the given name and reason:
expect(actual).to(raiseException(named: name, reason: reason))
I think that strict equality on things like reason
leads to brittle tests--in reality, I usually just want to make sure that the reason
of an exception contains a specific term. It'd be great if, instead, I could use matchers for each:
expect(actual).to(raiseException(
name: equal(NSInternalInconsistencyException),
localizedDescription: match("cannot be nil")
))
Thoughts? 🙌
When I try to install it with Cocoapods I get an error
[!] Pods written in Swift can only be integrated as frameworks; this feature is still in beta. Add use_frameworks!
to your Podfile or target to opt into using it.
To fix it I had to add use_frameworks!
to Podfile
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.