Skip to content

Moving the StreamTest to integration tests #391

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Oct 24, 2017

Conversation

schmidt-sebastian
Copy link
Contributor

This is meant to make #388 smaller.

_expectation = nil;
}

- (void)fulfillOnCallback:(XCTestExpectation *)expectation {
Copy link
Contributor

Choose a reason for hiding this comment

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

This name is off: the trailing part of the label should be "expectation" to match the argument on the other side of the type.

Meanwhile every usage of this

  • declares the expectation
  • calls _delegate fulfillOnCallback
  • does some async thing
  • calls await expectations

Why not write a routine that takes a block and wraps it with the first two steps then calls the block then finally awaits expectations.

Something like:

- (void)awaitCallbackInBlock:(blocktype)block {
  XCTestExpectation *openExpectation = [_testCase expectationWithDescription:@"awaiting"];
  [_delegate fulfillOnCallback:openExpectation];
  block();
  [_testCase awaitExpectations]; 
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Sounds good, done.

return [datastore createWatchStreamWithDelegate:_delegate];
}

- (void)verifyDelegate:(NSArray<NSString *> *)expectedStates {
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming: label should end in states. Perhaps verifyDelegateObservedStates?

When you're doing objective-C naming right each argument should be repeated two or three times: the label, type, and argument should align.

Sometimes the type differs because the label/argument are more specific than the type (as would be in this case).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done, thanks for the explanation.

}

- (void)tearDown {
[super tearDown];
Copy link
Contributor

Choose a reason for hiding this comment

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

You can omit this method if it's not doing anything.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done.

dispatch_sync(_testQueue, ^{
});

XCTAssertEqualObjects(_delegate.states, expectedStates);
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't this also remove the states accumulated in the delegate so that subsequent assertions only need to assert about the new states?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Hm, we can do this here, but it's not technically needed since delegate is scoped to the test.

Copy link
Contributor

Choose a reason for hiding this comment

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

delegate is scoped to the test but not clearing this means that you can't reasonably make more than one assertion. I'm also fine just leaving this alone until we need to do that, but just wanted the intent of my comment to be clear.

@schmidt-sebastian
Copy link
Contributor Author

Feedback addressed.

@@ -38,17 +38,25 @@ - (void)writesFinishedWithError:(NSError *_Nullable)error;
*/
@interface FSTStreamStatusDelegate : NSObject <FSTWatchStreamDelegate, FSTWriteStreamDelegate>

- (instancetype)initFrom:(XCTestCase *)testCase
Copy link
Contributor

Choose a reason for hiding this comment

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

Naming: first part of the label should end with "test case".

Also avoid connecting words in the labels for subsequent arguments unless they're critical to the meaning. It's appropriate in e.g. copyToFile:fromFile but not here, where you're just specifying the queue argument.

This should be: initWithTestCase:(XCTestCase *)testCase queue:(FSTDispatchQueue *)queue.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

This was inspired by the name in FEventTester. I updated it to use the naming you suggested and removed the 'using' part.

@property(nonatomic, readonly) NSMutableArray<NSString *> *states;
@property(atomic, readwrite) BOOL invokeCallbacks;
@property(nonatomic, weak) XCTestExpectation *expectation;
@property(nonatomic, weak, readonly) FSTStream *stream;
@property(nonatomic, weak, readonly) XCTestCase *testCase;
@property(nonatomic, weak, readonly) FSTDispatchQueue *dispatchQueue;
Copy link
Contributor

Choose a reason for hiding this comment

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

There are a lot of weak references in here which is a serious design smell. Are these actually necessary?

In general avoid weak references unless you specifically need them to break a reference cycle because they make your code very difficult to reason about.

In this case, you need the testCase to be weak because you're making this a member of that test case (which creates a cycle). The other things in here can be regular strong references.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It's enough for 'testCase' to be weak. Everything else is only retained by the test case itself as well as 'FSTStreamStatusDelegate'.

- (instancetype)initFrom:(XCTestCase *)testCase
usingQueue:(FSTDispatchQueue *)dispatchQueue NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;

@property(nonatomic, readonly) NSMutableArray<NSString *> *states;
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider splitting out implementation properties into a separate interface with an empty category (as is our convention elsewhere). As it stands it's not clear which of these are implementation state and which are meant to be used from within tests that use this delegate.

Copy link
Contributor Author

@schmidt-sebastian schmidt-sebastian Oct 23, 2017

Choose a reason for hiding this comment

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

The only public-facing property was 'invokeCallbacks', but I am actually not using it in this PR (and have removed it from the other one as well).

I tried moving the other properties into their own category, but it looks like I then need to create my getters and setters by hand (even @synthesize doesn't work). There's some discussion about this here: https://stackoverflow.com/questions/14399991/how-can-i-declare-a-private-property-within-a-named-category

@property(nonatomic, readonly) NSMutableArray<NSString *> *states;
@property(atomic, readwrite) BOOL invokeCallbacks;
@property(nonatomic, weak) XCTestExpectation *expectation;
@property(nonatomic, weak, readonly) FSTStream *stream;
@property(nonatomic, weak, readonly) XCTestCase *testCase;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: consider making your declaration order match your assignment order in the constructor, so it's easy to verify everything is assigned.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Done

dispatch_sync(_testQueue, ^{
});

XCTAssertEqualObjects(_delegate.states, expectedStates);
Copy link
Contributor

Choose a reason for hiding this comment

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

delegate is scoped to the test but not clearing this means that you can't reasonably make more than one assertion. I'm also fine just leaving this alone until we need to do that, but just wanted the intent of my comment to be clear.

Copy link
Contributor

@wilhuff wilhuff left a comment

Choose a reason for hiding this comment

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

This turned out really nicely. Thanks for pushing through all these changes.

Please verify the travis failure isn't real before submitting.

@schmidt-sebastian schmidt-sebastian merged commit 8bdce1d into master Oct 24, 2017
@schmidt-sebastian schmidt-sebastian deleted the mrschmidt-streamtests branch October 31, 2017 01:21
minafarid pushed a commit to minafarid/firebase-ios-sdk that referenced this pull request Jun 6, 2018
@firebase firebase locked and limited conversation to collaborators Nov 12, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants