Revealed on: November 28, 2024
In a earlier submit, I wrote about utilizing the #count on
macro to make sure that sure assertions you wish to make about your code are true. We checked out testing boolean circumstances in addition to errors.
On this submit, I would really like to try a macro that goes hand-in-hand with #count on
and that’s the #require
macro.
The #require
macro is used to make sure that sure circumstances in your take a look at are met, and to abort your take a look at if these circumstances should not met. The important thing distinction between #count on
and #require
is that #count on
won’t trigger a failed assertion to cease the take a look at.
#require
is far stricter. If we discover one assertion to be unfaithful inside the #require
macro, we finish the take a look at as a result of we do not assume it is sensible to check any additional.
On this submit, we’ll check out a number of functions of the #require
macro. For instance, we’ll use #require
to make sure that an non-compulsory worth could be unwrapped. We’ll additionally see how you should utilize #require
to make sure that a selected error is or will not be thrown. And naturally, we’ll additionally take a look at boolean circumstances inside #require
.
Let’s begin by taking a look at Non-obligatory
.
Unwrapping optionals with #require
Generally in our code we can have non-compulsory values. They’re just about unavoidable in Swift they usually’re truly a very useful gizmo. In your take a look at, it’s fairly doubtless that you will wish to guarantee that a sure worth exists earlier than continuing along with your take a look at. A technique to do that can be to make use of the #count on
macro and be sure that some property or worth will not be nil
.
Nevertheless, typically you may wish to take your non-compulsory worth and use it as enter for one thing else otherwise you wish to do additional testing with that object. In that case, it is sensible to abort your take a look at totally if the non-compulsory occurs to be nil
.
We will use the #require
macro for this, right here’s how:
@Check func userIsReturned() async throws {
let userStore = UserInfoStore()
let consumer = Consumer(title: "John")
userStore.addUser(consumer: consumer)
let returnedUser = strive #require(userStore.getUser(withName: "John"), "Consumer retailer ought to return the consumer that was added")
#count on(returnedUser == consumer, "Consumer retailer ought to return the consumer that was added")
}
The magic right here is on the road the place we create our let returnedUser
. We use the #require
macro and we name it with the strive
key phrase.
That is as a result of if the #require
macro fails to unwrap the non-compulsory that’s returned by getUser
, the macro will throw an error and so our take a look at will truly fail. That is fairly helpful while you actually do not wish to proceed your take a look at if no matter you are attempting to require is not there.
So on this case I wish to evaluate the return consumer with the one which I’ve tried to retailer. I can not try this if the consumer is not there. So I would like my take a look at to not simply fail when the non-compulsory that is returned by getUser
is nil
, I would like this take a look at case to finish.
Now let’s think about that I additionally wish to finish my take a look at if the returned consumer and the saved consumer aren’t the identical…
Checking boolean circumstances with #require
Within the earlier part I used the next to line to guarantee that my getUser
operate returned the right consumer:
#count on(returnedUser == consumer, "Consumer retailer ought to return the consumer that was added")
Discover how I am utilizing #count on
to check my returned consumer to my saved consumer.
This expectation will enable my take a look at to proceed operating even when the expectation fails. This might enable me to carry out a number of assertions on an object. For instance, if I have been to verify whether or not the consumer title, the consumer’s ID, and a bunch of different properties match, I’d use #count on
in order that I can carry out all assertions and see precisely which of them failed.
On this case I’d need my take a look at to fail and finish if I didn’t get the fitting consumer again.
So I am evaluating the 2 customers like earlier than and I’ve changed my #count on
with #require
. This is what that appears like in a full take a look at.
@Check func userIsReturned() async throws {
let userStore = UserInfoStore()
let consumer = Consumer(title: "John")
userStore.addUser(consumer: consumer)
let returnedUser = strive #require(userStore.getUser(withName: "John"), "Consumer retailer ought to return the consumer that was added")
strive #require(returnedUser == consumer, "Consumer retailer ought to return the consumer that was added")
print("this would possibly not run if I received the improper consumer")
}
Discover that I needed to prefix my #require
with the strive
key phrase, identical to I had for getting my returned consumer on the road earlier than.
The explanation for that’s if I did not get the fitting consumer again and it does not match with the consumer that I simply saved, my take a look at will throw an error and finish with a failure.
General, the APIs for #require
and #count on
are fairly comparable, with the important thing distinction being that #require
wants the strive
key phrase and your take a look at ends if a requirement is not met.
Now that we have seen how we are able to use this to unwrap optionals and verify boolean circumstances, the subsequent step is to see how we are able to use it to verify for sure errors being thrown.
Checking errors with #require
If you understand how to verify for errors with the #count on
macro, you mainly know it do with the #require
macro too.
The important thing distinction being as soon as once more if a requirement will not be met your take a look at case will cease.
If you wish to study extra about checking for errors, I urge you to try my weblog submit on the #count on
macro. I do not wish to duplicate the whole lot that is in there on this submit, so for an in-depth overview, you may check out that submit.
On this submit, I’d identical to to provide you a quick rundown of what it seems wish to verify for errors with the #require
macro.
So first let’s have a look at how we are able to assert that sure operate throws an anticipated error with the #require
macro.
I might be utilizing the identical instance that I used within the earlier submit. We will verify that giving an incorrect enter to an object will truly throw the error that I wish to obtain.
@Check func errorIsThrownForIncorrectInput() async throws {
let enter = -1
strive #require(throws: ValidationError.valueTooSmall(margin: 1), "Values between 0 and 100 ought to be okay") {
strive checkInput(enter)
}
}
On this particular instance, it won’t make a ton of sense to make use of #require
over #count on
. Nevertheless, if I have been to have extra code after this assertion and it would not make sense to proceed my take a look at if the improper error was thrown, then it makes whole sense for me to make use of #require
as a result of I wish to abandon the take a look at as a result of there isn’t any level in persevering with on.
Just like the #count on
macro, we are able to move a selected error (like I did within the instance above) or an error kind (like ValidationError.self
). If we wish to assert that no error is thrown, we may move By no means.self
because the error. kind to guarantee that our operate name doesn’t throw.
Just like the #count on
macro, you should utilize the #require
macro to verify whether or not a sure expression throws an error primarily based on a extra sophisticated analysis.
For all of the totally different overloads that exist on #require
, I want to redirect you to the #count on
macro submit as a result of they’re precisely the identical for #require
and #count on
. The important thing distinction is what occurs when the assertion fails: #count on
will enable your take a look at to proceed, however it can fail with an error on the road the place your assertion failed. With #require
, your take a look at case will merely finish on the road the place one thing that you simply did not count on truly occurred.
In Abstract
General, I fairly like that Swift testing permits us to have a free checking for assertions within the #count on
macro, the place we are able to validate that sure issues are or should not appropriate with out failing all the take a look at. That may mean you can make an entire bunch of assertions and see which of them fail, fixing one drawback at a time (operating your take a look at once more, fixing the subsequent drawback that reveals up) is tedious.
The #require
macro is very nice while you just about depend on one thing to be returned or one thing to be true earlier than you may proceed.
For instance, unwrapping an non-compulsory if you wish to use no matter you are attempting to unwrap to run additional code and carry out additional assertions. It is mindless to proceed your take a look at as a result of you already know that each single assertion that comes after it can fail, so I actually like utilizing #require
for these sorts of conditions and #count on
for those the place I can proceed my take a look at to gather extra details about the outcomes.