Skip to content
This repository has been archived by the owner on Dec 12, 2019. It is now read-only.

Modifies VOKMockUrlProtocol to allow for custom directory names #27

Open
wants to merge 5 commits into
base: master
Choose a base branch
from

Conversation

caleb-lee
Copy link

This PR modifies VOKMockUrlProtocol to allow for custom directory names for mock data.

It sets the default directory name to the forced name from before. You can easily change the directory name by subclassing VOKMockUrlProtocol and overriding -initWithRequest:cachedResponse:client and setting the directory name in that method. This offers the advantage of being able to change mocked server responses based on conditions.

@vokal/ios-developers code review please :)

…MockUrlProtocol and change the directory that mock data is stored in.
* It defaults to "VOKMockData", but its default can be overwritten by subclassing
* VOKMockUrlProtocol and overriding - initWithRequest:cachedResponse:client.
*/
@property (strong, nonatomic) NSString *mockDataDirectory;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should probably be copy rather than strong.

@vokal-isaac
Copy link
Contributor

Now that I think about it more, I suspect this won't work. NSURLProtocol classes are registered as a class and the system creates them internally, so I don't think the consumer of this class (i.e., the test bundle using it) will ever have the opportunity to set the property. Did you try this out to see if it worked? There's an example project in the Example directory that you could probably use for testing.

@caleb-lee
Copy link
Author

@vokal-isaac: the consumer of the class can subclass and set the property in initWithRequest:cachedResponse:client. This functionality is tested working.

As far as I know, without subclassing, there isn't any way to set the property.

@caleb-lee
Copy link
Author

Sorry about the commit weirdness? Totally misread @vokal-isaac's comment about the getter and thought it said setter instead. I didn't realize until after I pushed.

@vokal-isaac
Copy link
Contributor

I'm thinking something along the lines of this Stack Overflow answer—but this comment is more a bookmark for myself to come back to and actually explain what I'm thinking than something actionable.

@vokal-isaac
Copy link
Contributor

What I'm thinking is something along these lines:

In the header, inside the @interface:

+ (void)setMockDataDirectory:(NSString *)mockDataDirectory;
+ (NSString *)mockDataDirectory;  // This could be in an extension in the implementation file, but wouldn't hurt to have it here.

In the implementation file:

// Above the @implementation:
#import <objc/runtime.h>
static const void *MockDataDirectoryKey = &MockDataDirectoryKey;

// Inside the @implementation:
+ (void)setMockDataDirectory:(NSString *)mockDataDirectory
{
    objc_setAssociatedObject(self, ClientKey, client, OBJC_ASSOCIATION_COPY_NONATOMIC);
}

+ (NSString *)mockDataDirectory
{
    return objc_getAssociatedObject(self, ClientKey) ?: DefaultMockDataDirectory;
}

And wherever you've got self.mockDataDirectory now would become [[self class] mockDataDirectory].

This will mean that one could call [VOKMockUrlProtocol setMockDataDirectory:@"foo"]; to change the mock data directory to foo for anything using VOKMockUrlProtocol itself (not subclasses—subclasses wouldn't inherit changes in this setting) from the point of the method call until, say, [VOKMockUrlProtocol setMockDataDirectory:nil] is called to reset it to the default. One could also subclass VOKMockUrlProtocol and, in + initialize (or somewhere else suitable), call [self setMockDataDirectory:@"foo"] to have anything using the subclass look in foo for mock data.

@chillpop Do you have any thoughts on this approach?

@chillpop
Copy link
Contributor

@vokal-isaac, that sounds good. I would add some logic to look for files in an overridden mock data directory and the default mock data directory (in that order) so that we don't have to duplicate data files.

@caleb-lee, I think I changed my mind about exposing the default data directory string.

What I'd like to be able to do is set up my data like so:

VOKMockData
    POST|login.http
    GET|user.http
    differentMockData
        GET|user.http

So I can set the overridden mock data directory like so:

NSString differentDataDir = [VOKMockDataDirectory stringByAppendingPathComponent:@"differentMockData"];
[VOKMockURLProtocol setMockDataDirectory:differentDataDir];

And I have a login response that would get used even when I set the data directory to be the subdir.

@vokal-isaac
Copy link
Contributor

Maybe rather than a single directory, it should be an array of paths in which to search, in order?

@chillpop
Copy link
Contributor

The way I'm envisioning using this feature is to have a base of mock data that can get overridden for specific test suites/tests/requests. So you'd be changing the mock data directory possibly for each test or each request. In that usage pattern, having an array doesn't make sense.

Are you thinking of a different usage pattern?

@vokal-isaac
Copy link
Contributor

I'm thinking implementation-side, where if it's going to fall back to another location, my instinct is to implement it as an array of locations where it only checks the ones in the array and doesn't fall back to some unspecified default. I hadn't really thought about it from the usage-pattern side.

I'm also thinking that there might be headaches around folder nesting, but I may be misremembering something about how the files are loaded and how that all works.

@chillpop
Copy link
Contributor

Yes, for the implementation, an array makes sense. I guess I misunderstood your question.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants