Crucial Conversation

Leave a comment

Screen Shot 2017-01-25 at 5.35.31 AM.png

 

Just had a day of Spotify training around Crucial Conversation. It’s actually being quite good.

It outlines a process around which how one can prepare for a crucial conversation one is about to have. The part I liked the most was how to prepare your message in three simple steps.

  1. State the facts.
  2. Say how this makes your feel.
  3. Ask the other person how they feel, and whether you are way off.

The key is to do this sincerely, from the hear, and to assume good intentions. If you do this, you stand a much better chance achieving the dialog you are looking for.

You may not always get what you want. But at least you’ll set the right conversation up for where ever it is you are going.

Good luck!

Screen Shot 2017-01-24 at 5.03.09 AM.png

Screen Shot 2017-01-24 at 5.03.27 AM.png

The Way of the Web Tester

Leave a comment

Screen Shot 2016-09-15 at 5.45.37 AM.png

Hello everyone. A book I have been working on diligently for the last two years has finally hit the shelves. It’s called The Way of the Web Tester and it’s a book for anyone who wants to learn how to write automated tests for the web.

What’s in this book?

The book starts out by explaining what the three kinds of tests are that we typically see in web projects, along with some rules of them and guidance on where and when to use each.

We they spend a full two chapters at each level of something called the testing pyramid seeing how to add UI tests to legacy systems, how one can test web services, along with some rules of thumb around unit testing. That’s Part I.

Screen Shot 2016-09-15 at 6.25.50 AM.png

In Part II we build on the concepts outlined in the testing pyramid, but shift our focus to those skills specifically geared towards writing good tests.

First we look at some of the basics of programming, and show how by learning a few simple principles and practices we can dramatically increase the readability and maintainability of our automated tests.

We then look at some practices around test organization, and see how by simply grouping and organizing our tests in certain ways can make maintaining our tests so much easier.

And in the chapter on effective mocking, we look at some of the perils that come with this style of unit testing, and see how we can use mocks effectively while staying out of the swamp of mocking.

And we conclude with a section on the art of writing tests first. And see how beginning with the end in mind not only helps you test your systems, it can actually help you iterate on your design.

Who is this book for?

Screen Shot 2016-09-15 at 6.52.26 AM.png

If you are a tester who’s always wanted to get into test automation, this is the perfect book for taking that first step into a larger world.

If you are a developer, and you’d like to learn how to make your code even more robust, this book will show you how to move fast without breaking stuff.

And if you are team lead, looking better ways to get your testers and developers together, his is the Rosetta Stone you’ve been looking for.

Once your team has a common framework, language and understanding around automated testing, they will be able to better coordinate they’ll their efforts and write the best automated tests for your project.

So wait no further. Crush bugs. Move fast. And have fun. I hope you enjoy The Way of the Web Tester.

On sale now at all reputable book stores.

https://pragprog.com/book/jrtest/the-way-of-the-web-tester

https://www.amazon.com/Way-Web-Tester-Beginners-Automating/dp/1680501836

 

Objective-C – How to stub out an NSError unit test

Leave a comment

#import <XCTest/XCTest.h>

#import "Player.h"

// Mocking somethings (like NSError's) can be tricky in OCMockito.
// One alternative, if your mocks get too complex, is to simply manually stub.

// create a test class for the behaviour your want to stub,
// override the methods
// and then inject that into your SUT

// For example

// Test class we want to stub
@interface FakeHandler : Handler
- (BOOL)playTrack:(NSString *)track error:(NSError **)errorPtr;
- (BOOL)playAlbum:(NSString *)album error:(NSError **)errorPtr;
@end

@implementation FakeHandler

// Method / behaviour we want to override
- (BOOL)playTrack:(NSString *)track error:(NSError **)errorPtr {

    NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
    NSString *desc = NSLocalizedString(@"Unable to connect to network.", @"");
    NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };

    *errorPtr = [NSError errorWithDomain:domain
                                         code:-101
                                     userInfo:userInfo];

    return NO;
}

- (BOOL)playAlbum:(NSString *)album error:(NSError **)errorPtr {
    return NO;
}

@end


// Now we can use all of this in our test.

@interface PlayerStubTest : XCTestCase
@property (nonatomic, strong) Player *player;
@property (nonatomic, strong) Handler *fakeHandler;
@end

@implementation PlayerStubTest

- (void)setUp {
    [super setUp];
    self.fakeHandler = [FakeHandler new];
    self.player = [[Player alloc] initWithHandler:self.fakeHandler]; // Dependence inject our stub
}

- (void)testNetworkFailure {
    // Now when we call our play method, we can expect a failure and test that it bubbles up
    NSError *expectedError;
    [self.player playURL:@"track.xxx" error:&expectedError];
    XCTAssertNotNil(expectedError);
}

@end

How to throw and test exceptions in Objective-C

Leave a comment

PlayerTest.m

- (void)testInvalidUrl {
    XCTAssertThrows([self.player playURL:@"foobar" error:NULL], @"Invlaid url.");
}

Player.m

- (BOOL)playURL:(NSString *)url error:(NSError **)errorPtr {
    if ([url containsString:@"track"]) {
        return [self.handler playTrack:url error:errorPtr];
    } else if ([url containsString:@"album"]) {
        return [self.handler playAlbum:url error:errorPtr];
    } else {
        [NSException raise:@"Invalid url" format:@"%@ must be a track or an album.", url];
    }
    return NO;
}

Dealing with Errors in Objective-C

Leave a comment

A reminder to myself around where and when to use NSError vs throwing exception in Objective-C.

This article gives a nice summary

https://developer.apple.com/library/content/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/ErrorHandling/ErrorHandling.html

Use NSError for Most errors

When things go wrong in your app, due to

x network connectivity
x database been down etc

Use NSError and pass errors by reference.

- (BOOL)writeToURL:(NSURL *)aURL
 options:(NSDataWritingOptions)mask
 error:(NSError **)errorPtr;

Create an error pointer/reference and pass it to your method

NSError *anyError;
BOOL success = [receivedData writeToURL:someLocalFileURL options:0
 error:&anyError];

if (!success) {
 NSLog(@"Write failed with error: %@", anyError);
 // present error to user
}

The recover if possible and display an error to the user.

Generating your own errors

To create your own error define your own error domain.

com.companyName.appOrFrameworkName.ErrorDomain

Along with a unique error code for each error that may occur.

NSString *domain = @"com.MyCompany.MyApplication.ErrorDomain";
 NSString *desc = NSLocalizedString(@"Unable to…", @"");
 NSDictionary *userInfo = @{ NSLocalizedDescriptionKey : desc };
 
 NSError *error = [NSError errorWithDomain:domain
 code:-101
 userInfo:userInfo];

Then use as follows

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr;

- (BOOL)doSomethingThatMayGenerateAnError:(NSError **)errorPtr {
 ...
 // error occurred
 if (errorPtr) {
 *errorPtr = [NSError errorWithDomain:...
 code:...
 userInfo:...];
 }
 return NO;
}

Exceptions are Used for Programmer Errors

- (void)testInvalidUrl {
 XCTAssertThrows([self.player playURL:@"foobar" error:NULL], @"Invlaid url.");
}

- (BOOL)playURL:(NSString *)url error:(NSError **)errorPtr {
 if ([url containsString:@"track"]) {
 return [self.handler playTrack:url error:errorPtr];
 } else if ([url containsString:@"album"]) {
 return [self.handler playAlbum:url error:errorPtr];
 } else {
 [NSException raise:@"Invalid url" format:@"%@ must be a track or an album.", url];
 }
 return NO;
}

How to stub a class for unit testing

Leave a comment

Here is an example of how to override an existing class and create a stub for your unit tests in objective-c.

PlayerStubTest.m

#import <XCTest/XCTest.h>

#import "Player.h"
#import "Handler.h"

@interface PlayerStubTest : XCTestCase
@property (nonatomic, strong) Player *player;
@property (nonatomic, strong) Handler *stubHandler;
@end

// overide default behavior of handler for those methds you want to test
@interface StubHandler : Handler
- (BOOL)playTrack:(NSString *)track;
- (BOOL)playAlbum:(NSString *)album;
@end


@implementation StubHandler

- (BOOL)playTrack:(NSString *)track {
 NSLog(@"Stub track");
 return NO;
}

- (BOOL)playAlbum:(NSString *)album {
 NSLog(@"Stub albumn");
 return NO;
}

@end

@implementation PlayerStubTest

- (void)setUp {
 [super setUp];
 self.stubHandler = [StubHandler new];
 self.player = [[Player alloc] initWithHandler:self.stubHandler];
}

- (void)testExample {
 [self.player playURL:@"track"];
}

@end

 

When you run this you should see ‘Stub track’ in the console.

 

How to setup new iOS workflow

Leave a comment

  1. Install Xcode from the app store.
  2. Install Homebrew and its dependencies.
    $ ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
  3. Install a recent version of Git and CMake.
    $ brew install git cmake
  4. Upload your SSH key to Github
    1. Generate one if you haven’t already.
      $ ssh-keygen -t rsa -b 4096 -C "<email address>"
  5. Install a good .gitignore file.
    $ curl https://www.gitignore.io/api/objective-c >> ~/.gitignore
  6. Make sure git knows about it.
    $ git config --global core.excludesfile "~/.gitignore"
  7. Make sure Xcode removes trailing whitespace.
    $ defaults write com.apple.dt.Xcode DVTTextEditorTrimTrailingWhitespace 1
    $ defaults write com.apple.dt.Xcode DVTTextEditorTrimWhitespaceOnlyLines 1
    
    FORK

    1. Fork
    2. Clone your fork
    3. Add main (real repository) as your upstream remote.

    git remote add upstream git@ghe.xxx.net:/iOS/xxx-ios.git
    

    4. Disable pushes to upstream, to minimise the risk for mistakes

    git remote set-url --push upstream no_push
    

    5. Make sure git pushes to your fork by default.

    git config remote.pushdefault origin
    

    6. Make sure git only pushes the current branch.

    git config --global push.default simple
    

    7. set your master branch’s remote to upstream.

    git fetch upstream
    git branch --set-upstream-to=upstream/master master
    

    8. Then work

    git checkout master
    git pull upstream master
    git checkout -b my-fix
    

    9. Push the changes to your fork.

    git add .
    git commit -m
    git push -u origin my-fix
    

    10. If merging a PR to upstream conflicts, merge master to your branch and update the PR.

    git fetch upstream master
    git merge upstream/master
    

     

Older Entries

%d bloggers like this: