端端舝

端端舝Share a Scribd company logo
完我扼找抑快
unit-找快扼找抑
What makes a clean test?
Three things. Readability, readability, and readability.
Robert C. Martin, ?Clean Code?
#忱抉忌把我扮抗抉
- (void)testLoadAlbums {
NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil];
OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block);
[self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) {
OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]);
}];
}
4
- (void)testLoadAlbums {
NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil];
OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block);
[self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) {
OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]);
}];
}
5
- (void)testLoadAlbums {
NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil];
OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block);
[self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) {
OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]);
}];
}
6
- (void)testLoadAlbums {
NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil];
OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block);
[self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) {
OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]);
}];
}
7
- (void)testDeletingMessages {
NSMutableArray *messages = [NSMutableArray new];
NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread];
[messages addObject:message];
}
XCTestExpectation *expectation = [self expectationWithDescription:
[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]];
[self.service deleteMessages:messages withResultBlock:^(NSError *error) {
[expectation fulfill];
}];
}
8
- (void)testDeletingMessages {
NSMutableArray *messages = [NSMutableArray new];
NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread];
[messages addObject:message];
}
XCTestExpectation *expectation = [self expectationWithDescription:
[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]];
[self.service deleteMessages:messages withResultBlock:^(NSError *error) {
[expectation fulfill];
}];
}
9
- (void)testDeletingMessages {
NSMutableArray *messages = [NSMutableArray new];
NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread];
[messages addObject:message];
}
XCTestExpectation *expectation = [self expectationWithDescription:
[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]];
[self.service deleteMessages:messages withResultBlock:^(NSError *error) {
[expectation fulfill];
}];
}
10
- (void)testDeletingMessages {
NSMutableArray *messages = [NSMutableArray new];
NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread];
[messages addObject:message];
}
XCTestExpectation *expectation = [self expectationWithDescription:
[NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]];
[self.service deleteMessages:messages withResultBlock:^(NSError *error) {
[expectation fulfill];
}];
}
11
妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑
妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑
妓快扳忘抗找抉把我技 找快扼找
12
妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑
妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑
妓快扳忘抗找抉把我技 找快扼找
13
14
/**
@author Egor Tolstoy
妙快找抉忱 志抉戒志把忘投忘快找 戒忘抗快扮我把抉志忘扶扶抑快 把快戒批抖抆找忘找抑 扭抉我扼抗忘 忱抖攸 抉扭把快忱快抖快扶扶抉抄
扭抉我扼抗抉志抉抄 扼找把抉抗我
@param searchTerm 妤抉我扼抗抉志忘攸 扼找把抉抗忘
@return 妓快戒批抖抆找忘找抑 扭抉我扼抗忘
*/
- (NSArray *)obtainSearchResultsForSearchTerm:(NSString *)searchTerm;
15
@implementation PeopleServiceImplementationTests
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
@end
16
@implementation PeopleServiceImplementationTests
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
@end
17
@implementation PeopleServiceImplementationTests
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
@end
18
@implementation PeopleServiceImplementationTests
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
@end
19
@implementation PeopleServiceImplementationTests
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
- (void)testThatService {
}
@end
20
/**
妙快找抉忱 志抉戒志把忘投忘快找 戒忘抗快扮我把抉志忘扶扶抑快 把快戒批抖抆找忘找抑 扭抉我扼抗忘 忱抖攸 抉扭把快忱快抖快扶扶抉抄
扭抉我扼抗抉志抉抄 扼找把抉抗我
@param searchTerm 妤抉我扼抗抉志忘攸 扼找把抉抗忘
@return 妓快戒批抖抆找忘找抑 扭抉我扼抗忘
*/
+
...ServiceReturnsCachedSearchResultsForCorrectQuery
...ServiceReturnsNilWhenNoResults
...ServiceReturnsNilForInvalidCharacters
...ServiceInterpretsDashesAsUnderscores
21
坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 >
孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘
22
坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 >
孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘
23
坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 >
孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘
24
坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 >
孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘
25
妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑
妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑
妓快扳忘抗找抉把我技 找快扼找
26
完我扼找抑抄 找快扼找
扭把快忱技快找扶抉-抉把我快扶找我把抉志忘扶扶抑抄 攸戒抑抗
忌快戒 抖我扮扶快忍抉 抗抉扶找快抗扼找忘
找快扼找我把批快找扼攸 抉忱扶抉 扭抉志快忱快扶我快 扼我扼找快技抑
27
妤把快忱技快找扶抉-抉把我快扶找我把抉志忘扶扶抑抄 攸戒抑抗
孚抉把抉扮抉
XCTAssertEqualObjects(testAlbumError, expectedError);
- (void)testThatServiceReturnsNilWhenNoResults
[self setupStateWithBlockedUser];
妤抖抉抒抉
XCTAssertEqualObjects(err1, err2);
- (void)testNil
[self setupTestData];
28
妖快找 抖我扮扶快忍抉 抗抉扶找快抗扼找忘
孚抉把抉扮抉
[self stubServiceCompletionBlockWithError:error];
- (void)setUp {}
妤抖抉抒抉
...[invocation getArgument:&result atIndex:3];...
... self.interactor.output = OCMProtocolMock(...);...
29
妥快扼找我把批快技 抉忱扶抉 扭抉志快忱快扶我快
孚抉把抉扮抉
...
XCTAssertTrue(viewReloaded);
XCTAssertTrue(newDataIsShown);
妤抖抉抒抉
...
XCTAssertTrue(newUserSaved);
XCTAssertFalse(viewReloaded);
XCTAssertNil([self.service obtainSearchHistory]);
30
OCMExpect([self.mockView setupInitialStateWithMenuItems:[OCMArg checkWithBlock:^BOOL(NSArray
*menuItems) {
__block BOOL correctSelectors = YES;
[menuItems enumerateObjectsUsingBlock:^(ItemViewModel *menuItem, NSUInteger idx, BOOL stop) {
NSString *expectedSelector = selectors[idx];
if (![expectedSelector isEqualToString:NSStringFromSelector(menuItem.tapSelector)]) {
correctSelectors = NO;
}
}];
return correctSelectors && menuItems.count == selectors.count;
}]]);
31
OCMExpect([self.mockView setupInitialStateWithMenuItems:[OCMArg checkWithBlock:^BOOL(NSArray
*menuItems) {
__block BOOL correctSelectors = YES;
[menuItems enumerateObjectsUsingBlock:^(ItemViewModel *menuItem, NSUInteger idx, BOOL stop) {
NSString *expectedSelector = selectors[idx];
if (![expectedSelector isEqualToString:NSStringFromSelector(menuItem.tapSelector)]) {
correctSelectors = NO;
}
}];
return correctSelectors && menuItems.count == selectors.count;
}]]);
self.mockView = [MockMenuView new];
XCTAssertTrue(self.mockView.areAllSelectorsCorrect);
32
// 妊抖批折忘抄扶忘攸 扼找把抉抗忘
NSString *string = [[NSUUID UUID] UUIDString];
// 妤把抉我戒志抉抖抆扶忘攸 抉扮我忌抗忘
NSError *error = [NSError errorWithDomain:@"TestDomain" code:0 userInfo:nil];
33
// 妊抖批折忘抄扶忘攸 扼找把抉抗忘
NSString *string = [[NSUUID UUID] UUIDString];
// 妤把抉我戒志抉抖抆扶忘攸 抉扮我忌抗忘
NSError *error = [NSError errorWithDomain:@"TestDomain" code:0 userInfo:nil];
NSString *string = [MockGenerator generateMockString];
NSError *error = [MockGenerator generateMockError];
34
- (void)setUp {
[super setUp];
RamblerInitialAssemblyCollector *collector = [RamblerInitialAssemblyCollector new];
NSArray *assemblyClasses = [collector collectInitialAssemblyClasses];
NSMutableArray *collaboratingAssemblies = [NSMutableArray array];
for (Class assemblyClass in assemblyClasses) {
if (assemblyClass == [NetworkAssembly class]) {
continue;
}
TyphoonAssembly *assembly = [assemblyClass new];
[collaboratingAssemblies addObject:assembly];
}
NetworkAssembly *networkAssembly = [NetworkAssembly new];
[networkAssembly activateWithCollaboratingAssemblies:collaboratingAssemblies];
[networkAssembly inject:self];
}
35
- (void)setUp {
[super setUp];
RamblerInitialAssemblyCollector *collector = [RamblerInitialAssemblyCollector new];
NSArray *assemblyClasses = [collector collectInitialAssemblyClasses];
NSMutableArray *collaboratingAssemblies = [NSMutableArray array];
for (Class assemblyClass in assemblyClasses) {
if (assemblyClass == [NetworkAssembly class]) {
continue;
}
TyphoonAssembly *assembly = [assemblyClass new];
[collaboratingAssemblies addObject:assembly];
}
NetworkAssembly *networkAssembly = [NetworkAssembly new];
[networkAssembly activateWithCollaboratingAssemblies:collaboratingAssemblies];
[networkAssembly inject:self];
[MagicalRecord setupInMemoryCoreData];
}
- (void)setUp {
[self setUpWithAssemblyClass:[NetworkAssembly class]];
}
36
- (void)testThatServiceLoadsSessionProfileSuccessfully {
NSError *resultError;
// 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸
XCTAssertNil(resultError);
}
- (void)testThatServiceLoadsSessionProfileWithError {
NSError *expectedError = [MockObjectsFactory generateGeneralError];
// 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸
XCTAssertEqualObjects(resultError, expectedError);
}
37
- (void)testThatServiceLoadsSessionProfileSuccessfully {
NSError *resultError;
// 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸
XCTAssertNil(resultError);
}
- (void)testThatServiceLoadsSessionProfileWithError {
NSError *expectedError = [MockObjectsFactory generateGeneralError];
// 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸
XCTAssertEqualObjects(resultError, expectedError);
}
- (void)testThatServiceLoadsProfileSuccessfully {
[self verifyThatServiceLoadsProfileWithError:nil];
}
- (void)testThatServiceLoadsProfileWithError {
[self verifyThatServiceLoadsProfileWithError:error];
}
- (void)verifyThatServiceLoadsProfileWithError:(id)error {
...
}
38
- (void)testThatPresenterStartsObservePost {
NSString *postId = [MockObjectsFactory generateGeneralString];
[self.presenter configureCurrentModuleWithPostId:postId];
[self.presenter didTriggerViewReadyEvent];
OCMVerify([self.mockInteractor startObserveChangesWithPostId:postId]);
}
39
- (void)testThatPresenterStartsObservePost {
NSString *postId = [MockObjectsFactory generateGeneralString];
[self.presenter configureCurrentModuleWithPostId:postId];
[self.presenter didTriggerViewReadyEvent];
OCMVerify([self.mockInteractor startObserveChangesWithPostId:postId]);
}
- (void)testThatPresenterStartsObservePost {
// given
NSString *postId = [MockObjectsFactory generateGeneralString];
[self.presenter configureCurrentModuleWithPostId:postId];
// when
[self.presenter didTriggerViewReadyEvent];
// then
OCMVerify([self.mockInteractor startObserveChangesWithPostId:postId]);
}
40
妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑
妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑
妓快扳忘抗找抉把我技 找快扼找
41
OperationScheduler
queue1 queue2
NSOperation NSOperation
42
NSArray *operations = self.generalQueue.operations;
for (NSOperation *generalOperation in operations) {
[generalOperation addDependency:operation];
}
[self.authQueue addOperation:operation];
43
? 妤快把快忱忘快技 initialOperation 志 妤抖忘扶我把抉志投我抗
? 妤快把快忱忘快技 志 妤抖忘扶我把抉志投我抗 5 generalOperation
? 妤把我 志抑扭抉抖扶快扶我我 initialOperation 扼抉戒忱忘快找 authOperation
initial > authorization > general (5x)
44
- (void)testThatAuthOperationBlocksGeneralOperations {
// given
XCTestExpectation *expectation = [self expectationForCurrentTest];
NSMutableArray *operationNames = [NSMutableArray array];
NSString *const kAuthOperationName = @"AuthOperation";
NSString *const kInitialOperationName = @"InitialOperation";
NSString *const kGeneralOperationName = @"GeneralOperation";
NSUInteger const kGeneralOperationsCount = 5;
__block NSNumber *operationCounter = @0;
NSBlockOperation *authOperation = [NSBlockOperation blockOperationWithBlock:^{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(operationNames) {
[operationNames addObject:kAuthOperationName];
}
[NSThread sleepForTimeInterval:0.05];
});
}];
NSBlockOperation *initialOperation = [NSBlockOperation blockOperationWithBlock:^{
@synchronized(operationNames) {
[operationNames addObject:kInitialOperationName];
}
[self.scheduler addAuthOperation:authOperation];
}];
// when
[self.scheduler addGeneralOperation:initialOperation];
for (NSUInteger i = 0; i < kGeneralOperationsCount; i++) {
NSBlockOperation *generalOperation = [NSBlockOperation blockOperationWithBlock:^{
@synchronized(operationNames) {
[operationNames addObject:kGeneralOperationName];
}
@synchronized(operationCounter) {
operationCounter = @([operationCounter integerValue] + 1);
if ([operationCounter integerValue] == kGeneralOperationsCount) {
dispatch_async(dispatch_get_main_queue(), ^{
[expectation fulfill];
});
}
}
}];
[self.scheduler addGeneralOperation:generalOperation];
}
// then
[self waitForExpectationsWithTimeout:kTestExpectationTimeout handler:^(NSError *error) {
XCTAssertEqualObjects(operationNames[0], kInitialOperationName);
XCTAssertEqualObjects(operationNames[1], kAuthOperationName);
for (NSUInteger i = 2; i < kGeneralOperationsCount; i++) {
XCTAssertEqualObjects(operationNames[i], kGeneralOperationName);
}
}];
}
45
XCTestExpectation *expectation =
[self expectationWithDescription:@"Last operation fired"];
XCTestExpectation *expectation =
[self expectationForCurrentTest];
46
NSString *const kAuthOperationName = @"AuthOperation";
NSString *const kInitialOperationName = @"InitialOperation";
NSString *const kGeneralOperationName = @"GeneralOperation";
OperationSchedulerTestConstants.h
47
NSBlockOperation *authOperation = [NSBlockOperation withBlock:^{
dispatch_async(..., ^{
@synchronized(operationNames) {
[operationNames addObject:authName];
}
[NSThread sleep:0.05];
});
}];
48
@interface TestBlockingByAuthOperationEnvironment : NSObject
- (void)setupWithTestCase:(XCTestCase *)testCase
operationsCount:(NSUInteger)operationsCount
initialBlock:(Block)initialBlock;
@property NSBlockOperation *initialOperation;
@property NSBlockOperation *authOperation;
@property NSArray *generalOperations;
@property NSArray *firedOperationNames;
@end
49
TestBlockingByAuthOperationEnvironment *environment =
[TestBlockingByAuthOperationEnvironment new];
[environment setupWithTestCase:self
operationsCount:kGeneralOperationsCount
initialBlock:^{
[self.scheduler addAuthOperation:environment.authOperation];
for (NSOperation *operation in environment.generalOperations) {
[self.scheduler addGeneralOperation:operation];
}
}];
50
- (void)testThatAuthOperationBlocksGeneralOperations {
// given
NSUInteger const kGeneralOperationsCount = 5;
TestBlockingByAuthOperationEnvironment *environment = [TestBlockingByAuthOperationEnvironment new];
[environment setupEnvironmentWithTestCase:self
generalOperationsCount:kGeneralOperationsCount
initialOperationBlock:^{
[self.scheduler addAuthOperation:environment.authOperation];
for (NSOperation *operation in environment.generalOperations) {
[self.scheduler addGeneralOperation:operation];
}
}];
// when
[self.scheduler addGeneralOperation:environment.initialOperation];
// then
[self waitForExpectationsWithTimeout:kTestExpectationTimeout handler:^(NSError *error) {
[self verifyCorrectOperationOrder:kTestOrder];
}];
}
51
妤把快忱技快找扶抉-抉把我快扶找我把抉志忘扶扶抑抄 攸戒抑抗
妖快找 抖我扮扶快忍抉 抗抉扶找快抗扼找忘
妥快扼找我把批快技 抉忱扶抉 扭抉志快忱快扶我快
52
What makes a clean test?
Three things.
Readability, readability,
and readability.
圻忍抉把 妥抉抖扼找抉抄
@igrekde

More Related Content

What's hot (20)

JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentation
Anton Arhipov
?
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
SOAT
?
Testov芍n赤 prakticky
Testov芍n赤 praktickyTestov芍n赤 prakticky
Testov芍n赤 prakticky
Filip Proch芍zka
?
C++ Programming - 13th Study
C++ Programming - 13th StudyC++ Programming - 13th Study
C++ Programming - 13th Study
Chris Ohk
?
Collection pipeline par Mathieu Godart
Collection pipeline par  Mathieu GodartCollection pipeline par  Mathieu Godart
Collection pipeline par Mathieu Godart
CocoaHeads France
?
Lightning talk second
Lightning talk secondLightning talk second
Lightning talk second
ShinUsuda
?
Kruskal algorithm
Kruskal algorithmKruskal algorithm
Kruskal algorithm
Nguy?n C?ng Ho角ng
?
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tipsOpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
Ho Kim
?
Practical JavaScript Programming - Session 3/8
Practical JavaScript Programming - Session 3/8Practical JavaScript Programming - Session 3/8
Practical JavaScript Programming - Session 3/8
Wilson Su
?
JavaScript Assi?ncrono
JavaScript Assi?ncronoJavaScript Assi?ncrono
JavaScript Assi?ncrono
Nat? Barbosa
?
Java Thread Cronometro
Java Thread CronometroJava Thread Cronometro
Java Thread Cronometro
jubacalo
?
Sockets java
Sockets javaSockets java
Sockets java
Giovani Hernandez
?
Testes unit芍rios de JS com Jasmine e Karma
Testes unit芍rios de JS com Jasmine e KarmaTestes unit芍rios de JS com Jasmine e Karma
Testes unit芍rios de JS com Jasmine e Karma
Douglas Matoso
?
D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"
D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"
D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"
Dev2Dev
?
Rafael torrest
Rafael torrestRafael torrest
Rafael torrest
rfltorres
?
Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++
Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++
Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++
corehard_by
?
Ejb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.XEjb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.X
a19987225
?
Tugas pemrograman jaringan
Tugas pemrograman jaringanTugas pemrograman jaringan
Tugas pemrograman jaringan
Banser Sahara
?
JUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentationJUG.ua 20170225 - Java bytecode instrumentation
JUG.ua 20170225 - Java bytecode instrumentation
Anton Arhipov
?
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
RxJava, Getting Started - David Wursteisen - 16 Octobre 2014
SOAT
?
C++ Programming - 13th Study
C++ Programming - 13th StudyC++ Programming - 13th Study
C++ Programming - 13th Study
Chris Ohk
?
Collection pipeline par Mathieu Godart
Collection pipeline par  Mathieu GodartCollection pipeline par  Mathieu Godart
Collection pipeline par Mathieu Godart
CocoaHeads France
?
Lightning talk second
Lightning talk secondLightning talk second
Lightning talk second
ShinUsuda
?
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tipsOpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
OpenResty/Lua 70+ Advanced Programming Skills and Optimization tips
Ho Kim
?
Practical JavaScript Programming - Session 3/8
Practical JavaScript Programming - Session 3/8Practical JavaScript Programming - Session 3/8
Practical JavaScript Programming - Session 3/8
Wilson Su
?
JavaScript Assi?ncrono
JavaScript Assi?ncronoJavaScript Assi?ncrono
JavaScript Assi?ncrono
Nat? Barbosa
?
Java Thread Cronometro
Java Thread CronometroJava Thread Cronometro
Java Thread Cronometro
jubacalo
?
Testes unit芍rios de JS com Jasmine e Karma
Testes unit芍rios de JS com Jasmine e KarmaTestes unit芍rios de JS com Jasmine e Karma
Testes unit芍rios de JS com Jasmine e Karma
Douglas Matoso
?
D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"
D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"
D2D Pizza JS 妒忍抉把抆 妞抉志忍忘扶 "Koa 扭抉技抉忪快找"
Dev2Dev
?
Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++
Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++
Clang-tidy: 扭批找快扮快扼找志我快 志扶批找把抆 AST C++
corehard_by
?
Ejb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.XEjb 3.0 Glassfish 2.X Netbeans 6.X
Ejb 3.0 Glassfish 2.X Netbeans 6.X
a19987225
?
Tugas pemrograman jaringan
Tugas pemrograman jaringanTugas pemrograman jaringan
Tugas pemrograman jaringan
Banser Sahara
?

Viewers also liked (6)

2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS
2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS
2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS
妍技扼抗我快 妒妥-扼批忌忌抉找扶我抗我
?
Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我
Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我
Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我
RAMBLER&Co
?
Rambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la RamblerRambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la Rambler
RAMBLER&Co
?
Rambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPER
Rambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPERRambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPER
Rambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPER
RAMBLER&Co
?
Rambler.iOS #5: VIPER 我 Swift
Rambler.iOS #5: VIPER 我 SwiftRambler.iOS #5: VIPER 我 Swift
Rambler.iOS #5: VIPER 我 Swift
RAMBLER&Co
?
RDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 Swift
RDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 SwiftRDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 Swift
RDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 Swift
RAMBLER&Co
?
2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS
2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS
2016-08-20 02 均扶找抉扶 妞抉志忘抖快志, 均扶找抉扶 妞抉把技忘抗抉志. Viper. 完我扼找忘攸 忘把抒我找快抗找批把忘 忱抖攸 iOS
妍技扼抗我快 妒妥-扼批忌忌抉找扶我抗我
?
Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我
Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我
Rambler.iOS #5: 妤快把快抒抉忱抑 我 扭快把快忱忘折忘 忱忘扶扶抑抒 技快忪忱批 VIPER 技抉忱批抖攸技我
RAMBLER&Co
?
Rambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la RamblerRambler.iOS #5: VIPER a la Rambler
Rambler.iOS #5: VIPER a la Rambler
RAMBLER&Co
?
Rambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPER
Rambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPERRambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPER
Rambler.iOS #5: 妤抉忱技抉忱批抖我 志 VIPER
RAMBLER&Co
?
Rambler.iOS #5: VIPER 我 Swift
Rambler.iOS #5: VIPER 我 SwiftRambler.iOS #5: VIPER 我 Swift
Rambler.iOS #5: VIPER 我 Swift
RAMBLER&Co
?
RDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 Swift
RDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 SwiftRDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 Swift
RDSDataSource: 完我扼找抑快 找快扼找抑 扶忘 Swift
RAMBLER&Co
?

More from RAMBLER&Co (20)

RDSDataSource: 妍扼扶抉志抑 LLVM
RDSDataSource: 妍扼扶抉志抑 LLVMRDSDataSource: 妍扼扶抉志抑 LLVM
RDSDataSource: 妍扼扶抉志抑 LLVM
RAMBLER&Co
?
Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!
Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!
Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!
RAMBLER&Co
?
Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?
Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?
Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?
RAMBLER&Co
?
Rambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memoryRambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memory
RAMBLER&Co
?
RDSDataSource: OCLint
RDSDataSource: OCLintRDSDataSource: OCLint
RDSDataSource: OCLint
RAMBLER&Co
?
RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技
RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技
RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技
RAMBLER&Co
?
RDSDataSource: App Thinning
RDSDataSource: App ThinningRDSDataSource: App Thinning
RDSDataSource: App Thinning
RAMBLER&Co
?
RDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 Dip
RDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 DipRDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 Dip
RDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 Dip
RAMBLER&Co
?
RDSDataSource: YapDatabase
RDSDataSource: YapDatabaseRDSDataSource: YapDatabase
RDSDataSource: YapDatabase
RAMBLER&Co
?
Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘
Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘
Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘
RAMBLER&Co
?
Rambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCoreRambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCore
RAMBLER&Co
?
Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志
Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志
Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志
RAMBLER&Co
?
RDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperienced
RAMBLER&Co
?
RDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDK
RDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDKRDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDK
RDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDK
RAMBLER&Co
?
RDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOS
RDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOSRDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOS
RDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOS
RAMBLER&Co
?
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: Promises
RAMBLER&Co
?
RDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwift
RAMBLER&Co
?
Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘
Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘
Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘
RAMBLER&Co
?
Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我
Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我
Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我
RAMBLER&Co
?
Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101
Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101
Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101
RAMBLER&Co
?
RDSDataSource: 妍扼扶抉志抑 LLVM
RDSDataSource: 妍扼扶抉志抑 LLVMRDSDataSource: 妍扼扶抉志抑 LLVM
RDSDataSource: 妍扼扶抉志抑 LLVM
RAMBLER&Co
?
Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!
Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!
Rambler.iOS #9: 均扶忘抖我戒我把批抄 改找抉!
RAMBLER&Co
?
Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?
Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?
Rambler.iOS #9: 妖批忪扶抑 抖我 忌改抗快扶忱-把忘戒把忘忌抉找折我抗我, 抗抉忍忱忘 快扼找抆 Swift?
RAMBLER&Co
?
Rambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memoryRambler.iOS #9: Life with out of memory
Rambler.iOS #9: Life with out of memory
RAMBLER&Co
?
RDSDataSource: OCLint
RDSDataSource: OCLintRDSDataSource: OCLint
RDSDataSource: OCLint
RAMBLER&Co
?
RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技
RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技
RDSDataSource: 妤抉扼找把抉快扶我快 UML 忱我忘忍把忘技技
RAMBLER&Co
?
RDSDataSource: App Thinning
RDSDataSource: App ThinningRDSDataSource: App Thinning
RDSDataSource: App Thinning
RAMBLER&Co
?
RDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 Dip
RDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 DipRDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 Dip
RDSDataSource: 妙忘扼找快把-抗抖忘扼扼 扭抉 Dip
RAMBLER&Co
?
RDSDataSource: YapDatabase
RDSDataSource: YapDatabaseRDSDataSource: YapDatabase
RDSDataSource: YapDatabase
RAMBLER&Co
?
Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘
Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘
Rambler.iOS #8: 妊快把志我扼-抉把我快扶找我把抉志忘扶扶忘攸 忘把抒我找快抗找批把忘
RAMBLER&Co
?
Rambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCoreRambler.iOS #8: Make your app extensible with JavaScriptCore
Rambler.iOS #8: Make your app extensible with JavaScriptCore
RAMBLER&Co
?
Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志
Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志
Rambler.iOS #8: 妞忘抗 扶快 扼找忘找抆 忪快把找志抉抄 忌改抗快扶忱快把抉志
RAMBLER&Co
?
RDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperiencedRDSDataSource: iOS Reverse Engineering for inexperienced
RDSDataSource: iOS Reverse Engineering for inexperienced
RAMBLER&Co
?
RDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDK
RDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDKRDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDK
RDSDataSource: 均志找抉忍快扶快把忘扯我攸 忱抉抗批技快扶找忘扯我我 忱抖攸 SDK
RAMBLER&Co
?
RDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOS
RDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOSRDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOS
RDSDataSource: 妤抖攻把忘抖我戒忘扯我攸 志 iOS
RAMBLER&Co
?
RDSDataSource: Promises
RDSDataSource: PromisesRDSDataSource: Promises
RDSDataSource: Promises
RAMBLER&Co
?
RDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwiftRDSDataSource: Flux, Redux, ReSwift
RDSDataSource: Flux, Redux, ReSwift
RAMBLER&Co
?
Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘
Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘
Rambler.iOS #7: 妤抉扼找把抉快扶我快 扼抖抉忪扶抉忍抉 找忘忌抖我折扶抉忍抉 我扶找快把扳快抄扼忘
RAMBLER&Co
?
Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我
Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我
Rambler.iOS #7: 妤把我快技 扭抖忘找快忪快抄 扭抉 忌忘扶抗抉志扼抗我技 抗忘把找忘技 志 iOS 扭把我抖抉忪快扶我我
RAMBLER&Co
?
Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101
Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101
Rambler.iOS #7: 妒扶找快把扶快找-改抗志忘抄把我扶忍 101
RAMBLER&Co
?

Rambler.iOS #8: 完我扼找抑快 unit-找快扼找抑

  • 2. What makes a clean test? Three things. Readability, readability, and readability. Robert C. Martin, ?Clean Code?
  • 4. - (void)testLoadAlbums { NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil]; OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block); [self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) { OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]); }]; } 4
  • 5. - (void)testLoadAlbums { NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil]; OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block); [self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) { OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]); }]; } 5
  • 6. - (void)testLoadAlbums { NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil]; OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block); [self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) { OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]); }]; } 6
  • 7. - (void)testLoadAlbums { NSError *err1 = [NSError errorWithDomain:@"" code:123 userInfo:nil]; OCMStub([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]).andDo(block); [self waitForExpectationsWithTimeout:1. handler:^(NSError *localError) { OCMVerify([self.provider getAlbumsWithResultBlock:OCMOCK_ANY]); }]; } 7
  • 8. - (void)testDeletingMessages { NSMutableArray *messages = [NSMutableArray new]; NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread]; [messages addObject:message]; } XCTestExpectation *expectation = [self expectationWithDescription: [NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]]; [self.service deleteMessages:messages withResultBlock:^(NSError *error) { [expectation fulfill]; }]; } 8
  • 9. - (void)testDeletingMessages { NSMutableArray *messages = [NSMutableArray new]; NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread]; [messages addObject:message]; } XCTestExpectation *expectation = [self expectationWithDescription: [NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]]; [self.service deleteMessages:messages withResultBlock:^(NSError *error) { [expectation fulfill]; }]; } 9
  • 10. - (void)testDeletingMessages { NSMutableArray *messages = [NSMutableArray new]; NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread]; [messages addObject:message]; } XCTestExpectation *expectation = [self expectationWithDescription: [NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]]; [self.service deleteMessages:messages withResultBlock:^(NSError *error) { [expectation fulfill]; }]; } 10
  • 11. - (void)testDeletingMessages { NSMutableArray *messages = [NSMutableArray new]; NSManagedObjectContext *ctx = [NSManagedObjectContext MR_contextForCurrentThread]; [messages addObject:message]; } XCTestExpectation *expectation = [self expectationWithDescription: [NSString stringWithFormat:@"%s", __PRETTY_FUNCTION__]]; [self.service deleteMessages:messages withResultBlock:^(NSError *error) { [expectation fulfill]; }]; } 11
  • 12. 妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑 妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑 妓快扳忘抗找抉把我技 找快扼找 12
  • 13. 妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑 妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑 妓快扳忘抗找抉把我技 找快扼找 13
  • 14. 14
  • 15. /** @author Egor Tolstoy 妙快找抉忱 志抉戒志把忘投忘快找 戒忘抗快扮我把抉志忘扶扶抑快 把快戒批抖抆找忘找抑 扭抉我扼抗忘 忱抖攸 抉扭把快忱快抖快扶扶抉抄 扭抉我扼抗抉志抉抄 扼找把抉抗我 @param searchTerm 妤抉我扼抗抉志忘攸 扼找把抉抗忘 @return 妓快戒批抖抆找忘找抑 扭抉我扼抗忘 */ - (NSArray *)obtainSearchResultsForSearchTerm:(NSString *)searchTerm; 15
  • 16. @implementation PeopleServiceImplementationTests - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } @end 16
  • 17. @implementation PeopleServiceImplementationTests - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } @end 17
  • 18. @implementation PeopleServiceImplementationTests - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } @end 18
  • 19. @implementation PeopleServiceImplementationTests - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } @end 19
  • 20. @implementation PeopleServiceImplementationTests - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } - (void)testThatService { } @end 20
  • 21. /** 妙快找抉忱 志抉戒志把忘投忘快找 戒忘抗快扮我把抉志忘扶扶抑快 把快戒批抖抆找忘找抑 扭抉我扼抗忘 忱抖攸 抉扭把快忱快抖快扶扶抉抄 扭抉我扼抗抉志抉抄 扼找把抉抗我 @param searchTerm 妤抉我扼抗抉志忘攸 扼找把抉抗忘 @return 妓快戒批抖抆找忘找抑 扭抉我扼抗忘 */ + ...ServiceReturnsCachedSearchResultsForCorrectQuery ...ServiceReturnsNilWhenNoResults ...ServiceReturnsNilForInvalidCharacters ...ServiceInterpretsDashesAsUnderscores 21
  • 22. 坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 > 孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘 22
  • 23. 坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 > 孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘 23
  • 24. 坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 > 孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘 24
  • 25. 坐把攸戒扶抑快 找快扼找抑 > 妥攸忪快抖抉 扭抉忱忱快把忪我志忘找抆 > 孝忱忘抖快扶我快 找快扼找抉志 > 妤忘忱忘快找 抗忘折快扼找志抉 扭把抉快抗找忘 25
  • 26. 妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑 妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑 妓快扳忘抗找抉把我技 找快扼找 26
  • 27. 完我扼找抑抄 找快扼找 扭把快忱技快找扶抉-抉把我快扶找我把抉志忘扶扶抑抄 攸戒抑抗 忌快戒 抖我扮扶快忍抉 抗抉扶找快抗扼找忘 找快扼找我把批快找扼攸 抉忱扶抉 扭抉志快忱快扶我快 扼我扼找快技抑 27
  • 28. 妤把快忱技快找扶抉-抉把我快扶找我把抉志忘扶扶抑抄 攸戒抑抗 孚抉把抉扮抉 XCTAssertEqualObjects(testAlbumError, expectedError); - (void)testThatServiceReturnsNilWhenNoResults [self setupStateWithBlockedUser]; 妤抖抉抒抉 XCTAssertEqualObjects(err1, err2); - (void)testNil [self setupTestData]; 28
  • 29. 妖快找 抖我扮扶快忍抉 抗抉扶找快抗扼找忘 孚抉把抉扮抉 [self stubServiceCompletionBlockWithError:error]; - (void)setUp {} 妤抖抉抒抉 ...[invocation getArgument:&result atIndex:3];... ... self.interactor.output = OCMProtocolMock(...);... 29
  • 31. OCMExpect([self.mockView setupInitialStateWithMenuItems:[OCMArg checkWithBlock:^BOOL(NSArray *menuItems) { __block BOOL correctSelectors = YES; [menuItems enumerateObjectsUsingBlock:^(ItemViewModel *menuItem, NSUInteger idx, BOOL stop) { NSString *expectedSelector = selectors[idx]; if (![expectedSelector isEqualToString:NSStringFromSelector(menuItem.tapSelector)]) { correctSelectors = NO; } }]; return correctSelectors && menuItems.count == selectors.count; }]]); 31
  • 32. OCMExpect([self.mockView setupInitialStateWithMenuItems:[OCMArg checkWithBlock:^BOOL(NSArray *menuItems) { __block BOOL correctSelectors = YES; [menuItems enumerateObjectsUsingBlock:^(ItemViewModel *menuItem, NSUInteger idx, BOOL stop) { NSString *expectedSelector = selectors[idx]; if (![expectedSelector isEqualToString:NSStringFromSelector(menuItem.tapSelector)]) { correctSelectors = NO; } }]; return correctSelectors && menuItems.count == selectors.count; }]]); self.mockView = [MockMenuView new]; XCTAssertTrue(self.mockView.areAllSelectorsCorrect); 32
  • 33. // 妊抖批折忘抄扶忘攸 扼找把抉抗忘 NSString *string = [[NSUUID UUID] UUIDString]; // 妤把抉我戒志抉抖抆扶忘攸 抉扮我忌抗忘 NSError *error = [NSError errorWithDomain:@"TestDomain" code:0 userInfo:nil]; 33
  • 34. // 妊抖批折忘抄扶忘攸 扼找把抉抗忘 NSString *string = [[NSUUID UUID] UUIDString]; // 妤把抉我戒志抉抖抆扶忘攸 抉扮我忌抗忘 NSError *error = [NSError errorWithDomain:@"TestDomain" code:0 userInfo:nil]; NSString *string = [MockGenerator generateMockString]; NSError *error = [MockGenerator generateMockError]; 34
  • 35. - (void)setUp { [super setUp]; RamblerInitialAssemblyCollector *collector = [RamblerInitialAssemblyCollector new]; NSArray *assemblyClasses = [collector collectInitialAssemblyClasses]; NSMutableArray *collaboratingAssemblies = [NSMutableArray array]; for (Class assemblyClass in assemblyClasses) { if (assemblyClass == [NetworkAssembly class]) { continue; } TyphoonAssembly *assembly = [assemblyClass new]; [collaboratingAssemblies addObject:assembly]; } NetworkAssembly *networkAssembly = [NetworkAssembly new]; [networkAssembly activateWithCollaboratingAssemblies:collaboratingAssemblies]; [networkAssembly inject:self]; } 35
  • 36. - (void)setUp { [super setUp]; RamblerInitialAssemblyCollector *collector = [RamblerInitialAssemblyCollector new]; NSArray *assemblyClasses = [collector collectInitialAssemblyClasses]; NSMutableArray *collaboratingAssemblies = [NSMutableArray array]; for (Class assemblyClass in assemblyClasses) { if (assemblyClass == [NetworkAssembly class]) { continue; } TyphoonAssembly *assembly = [assemblyClass new]; [collaboratingAssemblies addObject:assembly]; } NetworkAssembly *networkAssembly = [NetworkAssembly new]; [networkAssembly activateWithCollaboratingAssemblies:collaboratingAssemblies]; [networkAssembly inject:self]; [MagicalRecord setupInMemoryCoreData]; } - (void)setUp { [self setUpWithAssemblyClass:[NetworkAssembly class]]; } 36
  • 37. - (void)testThatServiceLoadsSessionProfileSuccessfully { NSError *resultError; // 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸 XCTAssertNil(resultError); } - (void)testThatServiceLoadsSessionProfileWithError { NSError *expectedError = [MockObjectsFactory generateGeneralError]; // 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸 XCTAssertEqualObjects(resultError, expectedError); } 37
  • 38. - (void)testThatServiceLoadsSessionProfileSuccessfully { NSError *resultError; // 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸 XCTAssertNil(resultError); } - (void)testThatServiceLoadsSessionProfileWithError { NSError *expectedError = [MockObjectsFactory generateGeneralError]; // 忌抉抖抆扮抉抄 忌抖抉抗 抖抉忍我抗我 戒忘忍把批戒抗我 扭把抉扳我抖攸 XCTAssertEqualObjects(resultError, expectedError); } - (void)testThatServiceLoadsProfileSuccessfully { [self verifyThatServiceLoadsProfileWithError:nil]; } - (void)testThatServiceLoadsProfileWithError { [self verifyThatServiceLoadsProfileWithError:error]; } - (void)verifyThatServiceLoadsProfileWithError:(id)error { ... } 38
  • 39. - (void)testThatPresenterStartsObservePost { NSString *postId = [MockObjectsFactory generateGeneralString]; [self.presenter configureCurrentModuleWithPostId:postId]; [self.presenter didTriggerViewReadyEvent]; OCMVerify([self.mockInteractor startObserveChangesWithPostId:postId]); } 39
  • 40. - (void)testThatPresenterStartsObservePost { NSString *postId = [MockObjectsFactory generateGeneralString]; [self.presenter configureCurrentModuleWithPostId:postId]; [self.presenter didTriggerViewReadyEvent]; OCMVerify([self.mockInteractor startObserveChangesWithPostId:postId]); } - (void)testThatPresenterStartsObservePost { // given NSString *postId = [MockObjectsFactory generateGeneralString]; [self.presenter configureCurrentModuleWithPostId:postId]; // when [self.presenter didTriggerViewReadyEvent]; // then OCMVerify([self.mockInteractor startObserveChangesWithPostId:postId]); } 40
  • 41. 妝忘折快技 扶批忪扶抑 折我扼找抑快 找快扼找抑 妞忘抗 扭我扼忘找抆 折我扼找抑快 找快扼找抑 妓快扳忘抗找抉把我技 找快扼找 41
  • 43. NSArray *operations = self.generalQueue.operations; for (NSOperation *generalOperation in operations) { [generalOperation addDependency:operation]; } [self.authQueue addOperation:operation]; 43
  • 44. ? 妤快把快忱忘快技 initialOperation 志 妤抖忘扶我把抉志投我抗 ? 妤快把快忱忘快技 志 妤抖忘扶我把抉志投我抗 5 generalOperation ? 妤把我 志抑扭抉抖扶快扶我我 initialOperation 扼抉戒忱忘快找 authOperation initial > authorization > general (5x) 44
  • 45. - (void)testThatAuthOperationBlocksGeneralOperations { // given XCTestExpectation *expectation = [self expectationForCurrentTest]; NSMutableArray *operationNames = [NSMutableArray array]; NSString *const kAuthOperationName = @"AuthOperation"; NSString *const kInitialOperationName = @"InitialOperation"; NSString *const kGeneralOperationName = @"GeneralOperation"; NSUInteger const kGeneralOperationsCount = 5; __block NSNumber *operationCounter = @0; NSBlockOperation *authOperation = [NSBlockOperation blockOperationWithBlock:^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ @synchronized(operationNames) { [operationNames addObject:kAuthOperationName]; } [NSThread sleepForTimeInterval:0.05]; }); }]; NSBlockOperation *initialOperation = [NSBlockOperation blockOperationWithBlock:^{ @synchronized(operationNames) { [operationNames addObject:kInitialOperationName]; } [self.scheduler addAuthOperation:authOperation]; }]; // when [self.scheduler addGeneralOperation:initialOperation]; for (NSUInteger i = 0; i < kGeneralOperationsCount; i++) { NSBlockOperation *generalOperation = [NSBlockOperation blockOperationWithBlock:^{ @synchronized(operationNames) { [operationNames addObject:kGeneralOperationName]; } @synchronized(operationCounter) { operationCounter = @([operationCounter integerValue] + 1); if ([operationCounter integerValue] == kGeneralOperationsCount) { dispatch_async(dispatch_get_main_queue(), ^{ [expectation fulfill]; }); } } }]; [self.scheduler addGeneralOperation:generalOperation]; } // then [self waitForExpectationsWithTimeout:kTestExpectationTimeout handler:^(NSError *error) { XCTAssertEqualObjects(operationNames[0], kInitialOperationName); XCTAssertEqualObjects(operationNames[1], kAuthOperationName); for (NSUInteger i = 2; i < kGeneralOperationsCount; i++) { XCTAssertEqualObjects(operationNames[i], kGeneralOperationName); } }]; } 45
  • 46. XCTestExpectation *expectation = [self expectationWithDescription:@"Last operation fired"]; XCTestExpectation *expectation = [self expectationForCurrentTest]; 46
  • 47. NSString *const kAuthOperationName = @"AuthOperation"; NSString *const kInitialOperationName = @"InitialOperation"; NSString *const kGeneralOperationName = @"GeneralOperation"; OperationSchedulerTestConstants.h 47
  • 48. NSBlockOperation *authOperation = [NSBlockOperation withBlock:^{ dispatch_async(..., ^{ @synchronized(operationNames) { [operationNames addObject:authName]; } [NSThread sleep:0.05]; }); }]; 48
  • 49. @interface TestBlockingByAuthOperationEnvironment : NSObject - (void)setupWithTestCase:(XCTestCase *)testCase operationsCount:(NSUInteger)operationsCount initialBlock:(Block)initialBlock; @property NSBlockOperation *initialOperation; @property NSBlockOperation *authOperation; @property NSArray *generalOperations; @property NSArray *firedOperationNames; @end 49
  • 50. TestBlockingByAuthOperationEnvironment *environment = [TestBlockingByAuthOperationEnvironment new]; [environment setupWithTestCase:self operationsCount:kGeneralOperationsCount initialBlock:^{ [self.scheduler addAuthOperation:environment.authOperation]; for (NSOperation *operation in environment.generalOperations) { [self.scheduler addGeneralOperation:operation]; } }]; 50
  • 51. - (void)testThatAuthOperationBlocksGeneralOperations { // given NSUInteger const kGeneralOperationsCount = 5; TestBlockingByAuthOperationEnvironment *environment = [TestBlockingByAuthOperationEnvironment new]; [environment setupEnvironmentWithTestCase:self generalOperationsCount:kGeneralOperationsCount initialOperationBlock:^{ [self.scheduler addAuthOperation:environment.authOperation]; for (NSOperation *operation in environment.generalOperations) { [self.scheduler addGeneralOperation:operation]; } }]; // when [self.scheduler addGeneralOperation:environment.initialOperation]; // then [self waitForExpectationsWithTimeout:kTestExpectationTimeout handler:^(NSError *error) { [self verifyCorrectOperationOrder:kTestOrder]; }]; } 51
  • 52. 妤把快忱技快找扶抉-抉把我快扶找我把抉志忘扶扶抑抄 攸戒抑抗 妖快找 抖我扮扶快忍抉 抗抉扶找快抗扼找忘 妥快扼找我把批快技 抉忱扶抉 扭抉志快忱快扶我快 52
  • 53. What makes a clean test? Three things. Readability, readability, and readability. 圻忍抉把 妥抉抖扼找抉抄 @igrekde