Kiwi: Is there a way to have a dynamic number of example, defined by a runtime variable?

279 Views Asked by At

I'm looking for a way to test properties of nested objects. In essence, I have a spec the will verify the result we get back from an external service. Since I don't want to make a gazillion calls to the service for each example I want to test, the request is made once in the beginning of the spec, and then we a set of expectations verifying the response.

Best explained with a code sample (which doesn't work as intended, obviously):

    beforeAll(^{
        wait = [self waitFor:^(id handler) { [session.account all:handler]; }];
        accounts = wait.result;
    });

    it(@"should make a successfull request", ^{
        [[wait should] beSuccessful];
    });

    it(@"returns a non-nil list of accounts", ^{
        [[accounts shouldNot] beNil];
    });

    it(@"should have at least 1 account", ^{
        [[[accounts.accounts should] haveAtLeast:1] account];
    }); 

    context(@"each account", ^{
        for (Account* account in accounts.accounts) {
            it(@"should have a name", ^{
                [[account.name shouldNot] beEmpty];
            });
            it(@"should have an accountID", ^{
                [[account.accountID shouldNot] equal:@"bla"];
            });
        }
    });
});

It's the "each account" context I'm interested in. Basically, the call returns a set of accounts, and I want the validity of each of them.

I could turn this around and have the loops in the it() blocks, and that kinda works, but it doesn't tell me which item was faulty, and all verifiers run after a faulty one (eg when encountering at nil account.name) return the Trying to add another verifier without specifying a matcher for the previous one. error. So, not really useful.

I thought about just testing the returned json, because there's also a set of specs we have for (unit-)testing our own components irregardless of the response we get from the service. But that doesn't work, since we don't really care about the exact set of data (which also is prone to change), it's just that the format should be correct.

When writing a spec with local testdata, I'd write several specs for each level in the hierarchy, but I want to have this together: I'd like to test the one response received from the server in it's entirety.

I've tried doing this dynamically by adding more KWExamples when the test is running, but that doesn't seem to work.

Any idea (or am I misusing this for something it wasn't intended to do)?

(also posted as a Github issue: https://github.com/allending/Kiwi/issues/435)

1

There are 1 best solutions below

1
On

Each spec needs to be an unique name. In your example you're adding x specs with the same name. I think it is better to have only 2 specs. Just iterate your array in both:

context(@"each account", ^{
    it(@"should have a name", ^{
       for (Account* account in accounts.accounts) {
            [[account.name shouldNot] beEmpty];
       }
    });
    it(@"should have an accountID", ^{
       for (Account* account in accounts.accounts) {
            [[account.accountID shouldNot] equal:@"bla"];
       }
    });
});