Skip to content

Commit

Permalink
Device Fakes
Browse files Browse the repository at this point in the history
  • Loading branch information
orta committed Mar 31, 2016
1 parent 709c566 commit 780538e
Show file tree
Hide file tree
Showing 18 changed files with 183 additions and 56 deletions.
30 changes: 17 additions & 13 deletions CONTRIBUTING.md
@@ -1,47 +1,51 @@
#### How can I contribute to this book?
## How can I contribute to this book?

There's a bunch of things I've not covered, and there's still a lot of work to do based on my current Table Of Contents, which currently lets you see how each chapters is doing with respect to word count. Ideally most topics should come to around ~300 - 500 words.
There's a bunch of things I've not covered, and there's still a lot of work to do based on my current Table Of Contents (README), which currently lets you see how each chapters is doing with respect to word count. Ideally most topics should come to around ~300 - 500 words.

I'm happy to have other people send pull requests to the book, adding or amending chapters. Here's my general rules:

* Strive for Real-World Examples
* **Strive for Real-World Examples**
No `foo = bar`- even better if you can take it directly from an OSS code-base and reference it.

Talk about personal experiences with ideas, and their trade-offs. It's great that you can test everything, but if it comes at the trade-off of a time intensive test suite. Let people know.
Talk about personal experiences with ideas, and their trade-offs. It's great that you can test everything, but if it comes at the trade-off of a time intensive test-suite. Let people know.

* Down to Earth
* **Down to Earth**
Functional programming, protocol oriented programming, Reactive Programming, MVVM, etc. etc. - are all nice, but this book isn't for architecture astronauts. We want to be sticking with the well-known, well documented classics.

Write like you talk, this isn't going to be published by a fancy publisher, so it should be in a casual tone.

* Simplicity Ships
* **Simplicity Ships**
This project is like, a million months overdue. Don't faff with changing formats or adding extra engineering work to "make things easier to write."

Also, seriously, don't try making or improving a text editor just for this. Just use TextMate, with markdown, and "Deal with it."

This makes life easier:

``` shell
mkdir -p ~/Library/Application\ Support/Avian/Bundles
cd ~/Library/Application\ Support/Avian/Bundles
git clone https://github.com/mikemcquaid/GitHub-Markdown.tmbundle
```

* Be Opinionated
* **Be Opinionated**
Presenting options for anything is fine, but this book is about being pragmatic, not providing a tonne of sites to read through before being able to make a decision.

* Ship Before Promises
* **Ship Before Promises**
I've had a lot of offers on other projects around interesting things like translations, of course I'm interested, but without proof that it's both being done, and going to get completed - it's not worth breaking "Simplicity Ships." I've got a bunch of semi-translated projects that were abandoned.

* Issues before new chapters
Don't worry about the style of the ebook, or whether you're using the right amount of `####`s until the book is ready, it's much easier to figure out the style once there is something to work with. It's got a pretty cover image, that's enough.

* **Issues before new chapters**
Each chapter takes a good long time to write, and if you've spent a long time on something which I don't think is a good pragmatic testing pattern, then that's gonna be a shame to waste your time.

If you're not sure, make an issue and ask. It is my name on the book, and I have to deal with repercussions / maintaining your chapters.

* Things I Obsess Over
* **Things I Obsess Over**

* Time it takes to run the test suite
* Time it takes to run the test-suite
* Simplicity to test, without strongly affecting maintainability

* Things I Don't Obsess Over
* **Things I Don't Obsess Over**

* Testing every last detail
* Being right all the time
Expand All @@ -50,6 +54,6 @@ I'm happy to have other people send pull requests to the book, adding or amendin

All the book generation is done via code, in ruby via the `generate.rb` file and the `generators` folder. It's ruby, because it pre-dates Swift being a useful language.

Running `ruby generate.rb` will create an epub ( if you have `pandoc` installed (`brew install pandoc`)) generate all the files for the [GitBook](https://www.gitbook.com/book/orta/pragmatic-ios-testing/details) and update the `README.md`.
Running `ruby generate.rb` will create an ePub ( if you have `pandoc` installed (`brew install pandoc`)) generate all the files for the [GitBook](https://www.gitbook.com/book/orta/pragmatic-ios-testing/details) and update the `README.md`.

The file `generators/structure_of_pragmatic_programming.rb` contains all the path `->` chapter mapping, running `ruby generate.rb` will complain about missing paths/chapters.
32 changes: 17 additions & 15 deletions README.md
Expand Up @@ -11,27 +11,27 @@ Wanna contribute? [read this](CONTRIBUTING.md).

##### Existing Pages

| Topic | Last Updated | State | Length |
| -------|------|--|-----|
|[What Is/What And Why Of The Book](chapters/en-UK/what_is/what_and_why_of_the_book.md)|2016-03-31|💌|Words: 518|
|[What Is/How Can I Be Pragmatic With My Testing](chapters/en-UK/what_is/how_can_i_be_pragmatic_with_my_testing.md)|2016-03-31|💌|Words: 370|
|[XCTest/What Is XCTest How Does It Work](chapters/en-UK/xctest/what_is_xctest_how_does_it_work.md)|2016-03-31|💌|Words: 573|
| Topic | Last Updated | State | Length |
| -------|------|---|-----|
|[What Is/What And Why Of The Book](chapters/en-UK/what_is/what_and_why_of_the_book.md)|2016-03-31|💌|Words: 517|
|[What Is/How Can I Be Pragmatic With My Testing](chapters/en-UK/what_is/how_can_i_be_pragmatic_with_my_testing.md)|2016-03-31|💌|Words: 368|
|[XCTest/What Is XCTest How Does It Work](chapters/en-UK/xctest/what_is_xctest_how_does_it_work.md)|2016-03-31|💌|Words: 571|
|[XCTest/Types Of Testing](chapters/en-UK/xctest/types_of_testing.md)|2016-03-31|💌|Words: 340|
|[XCTest/Unit Testing](chapters/en-UK/xctest/unit_testing.md)|2016-03-31|💌|Words: 336|
|[XCTest/Behavior Testing](chapters/en-UK/xctest/behavior_testing.md)|2016-03-31|💌|Words: 1228|
|[XCTest/Three Types Of Unit Tests](chapters/en-UK/xctest/Three_Types_of_Unit_Tests.md)|2016-03-31|💌|Words: 314|
|[XCTest/Three Types Of Unit Tests](chapters/en-UK/xctest/three_types_of_unit_tests.md)||💌|Words: 357|
|[XCTest/Behavior Testing](chapters/en-UK/xctest/behavior_testing.md)|2016-03-31|💌|Words: 1227|
|[XCTest/Test Driven Development](chapters/en-UK/xctest/test_driven_development.md)|2016-03-31|💌|Words: 449|
|[XCTest/Integration Testing](chapters/en-UK/xctest/integration_testing.md)|2016-03-31|💌|Words: 536|
|[XCTest/Integration Testing](chapters/en-UK/xctest/integration_testing.md)|2016-03-31|💌|Words: 535|
|[Foundations/Dependency Injection](chapters/en-UK/foundations/dependency_injection.md)|2016-03-31|💌|Words: 806|
|[Foundations/Stubs Mocks And Fakes](chapters/en-UK/foundations/stubs_mocks_and_fakes.md)|2016-03-31|💌|Words: 475|
|[Foundations/Stubs Mocks And Fakes](chapters/en-UK/foundations/stubs_mocks_and_fakes.md)|2016-03-31|💌|Words: 474|
|[OSS Libs/Expanding On Bdd Frameworks](chapters/en-UK/oss_libs/expanding_on_bdd_frameworks.md)|2016-03-31|✍🏾|Words: 3|
|[OSS Libs/Mocking And Stubbing Ocmock And Ocmockito ](chapters/en-UK/oss_libs/mocking_and_stubbing__ocmock_and_ocmockito_.md)|2016-03-31|✍🏾|Words: 0|
|[OSS Libs/Network Stubbing Ohttp And Vcrurlconnection](chapters/en-UK/oss_libs/network_stubbing__ohttp_and_vcrurlconnection.md)|2016-03-31|✍🏾|Words: 0|
|[Setup/Getting Setup](chapters/en-UK/setup/getting_setup.md)|2016-03-31|💌|Words: 313|
|[Setup/How I Got Started](chapters/en-UK/setup/how_i_got_started.md)|2016-03-31|💌|Words: 333|
|[Setup/Starting A New Application And Using Tests](chapters/en-UK/setup/starting_a_new_application_and_using_tests.md)|2016-03-31|✍🏾|Words: 0|
|[Setup/Starting A New Application And Using Tests](chapters/en-UK/setup/starting_a_new_application_and_using_tests.md)|2016-03-31|💌|Words: 498|
|[Setup/Introducing Tests Into An Existing Application](chapters/en-UK/setup/introducing_tests_into_an_existing_application.md)|2016-03-31|💌|Words: 337|
|[Ops/Developer Operations Aka Automation](chapters/en-UK/ops/developer_operations_aka_automation.md)|2016-03-31|💌|Words: 1275|
|[Ops/Developer Operations Aka Automation](chapters/en-UK/ops/developer_operations_aka_automation.md)|2016-03-31|💌|Words: 1274|
|[Ops/Techniques For Keeping Testing Code Sane](chapters/en-UK/ops/techniques_for_keeping_testing_code_sane.md)|2016-03-31|✍🏾|Words: 0|
|[Ops/Creation Of App-Centric It Blocks](chapters/en-UK/ops/creation_of_app-centric_it_blocks.md)|2016-03-31|✍🏾|Words: 0|
|[Ops/Fixtures And Factories](chapters/en-UK/ops/fixtures_and_factories.md)|2016-03-31|✍🏾|Words: 0|
Expand All @@ -42,10 +42,10 @@ Wanna contribute? [read this](CONTRIBUTING.md).
|[Async/Animations](chapters/en-UK/async/animations.md)|2016-03-31|📎|Words: 148|
|[Async/Will And XCTest 6](chapters/en-UK/async/will_and_xctest_6.md)|2016-03-31|✍🏾|Words: 0|
|[App Testing/Techniques For Testing Different Aspects Of The App](chapters/en-UK/app_testing/techniques_for_testing_different_aspects_of_the_app.md)|2016-03-31|✍🏾|Words: 0|
|[App Testing/Views Snapshots](chapters/en-UK/app_testing/views__snapshots.md)|2016-03-31|📎|Words: 181|
|[App Testing/Views Snapshots](chapters/en-UK/app_testing/views__snapshots.md)|2016-03-31|📎|Words: 189|
|[App Testing/Scroll Views](chapters/en-UK/app_testing/scroll_views.md)|2016-03-31|✍🏾|Words: 0|
|[App Testing/User Interactions](chapters/en-UK/app_testing/user_interactions.md)|2016-03-31|✍🏾|Words: 7|
|[App Testing/Ipad And Iphone](chapters/en-UK/app_testing/ipad_and_iphone.md)|2016-03-31|✍🏾|Words: 0|
|[App Testing/Ipad And Iphone](chapters/en-UK/app_testing/ipad_and_iphone.md)|2016-03-31|📋|Words: 284|
|[App Testing/Testing Delegates](chapters/en-UK/app_testing/testing_delegates.md)|2016-03-31|💌|Words: 490|
|[Core Data/Core Data](chapters/en-UK/core_data/core_data.md)|2016-03-31|💌|Words: 778|
|[Core Data/Core Data Migrations](chapters/en-UK/core_data/core_data_migrations.md)|2016-03-31|💌|Words: 490|
Expand All @@ -57,8 +57,10 @@ Wanna contribute? [read this](CONTRIBUTING.md).
|[Wrap Up/Recommended Websites](chapters/en-UK/wrap_up/recommended_websites.md)|2016-03-31|✍🏾|Words: 51|


Over 200 words: 50.0%
Over 300 words: 50.0%
Over 200 words: 54.8%
Over 300 words: 52.4%
TODOs: 10


##### Generating the ebook

Expand Down
2 changes: 1 addition & 1 deletion SUMMARY.md
Expand Up @@ -5,8 +5,8 @@
* [Chapters/En-Uk/Xctest/What Is Xctest How Does It Work](chapters/en-UK/xctest/what_is_xctest_how_does_it_work.md)
* [Chapters/En-Uk/Xctest/Types Of Testing](chapters/en-UK/xctest/types_of_testing.md)
* [Chapters/En-Uk/Xctest/Unit Testing](chapters/en-UK/xctest/unit_testing.md)
* [Chapters/En-Uk/Xctest/Three Types Of Unit Tests](chapters/en-UK/xctest/three_types_of_unit_tests.md)
* [Chapters/En-Uk/Xctest/Behavior Testing](chapters/en-UK/xctest/behavior_testing.md)
* [Chapters/En-Uk/Xctest/Three Types Of Unit Tests](chapters/en-UK/xctest/Three_Types_of_Unit_Tests.md)
* [Chapters/En-Uk/Xctest/Test Driven Development](chapters/en-UK/xctest/test_driven_development.md)
* [Chapters/En-Uk/Xctest/Integration Testing](chapters/en-UK/xctest/integration_testing.md)
* [Chapters/En-Uk/Foundations/Dependency Injection](chapters/en-UK/foundations/dependency_injection.md)
Expand Down
67 changes: 67 additions & 0 deletions chapters/en-UK/app_testing/ipad_and_iphone.md
@@ -0,0 +1,67 @@
### Multi-Device Support

There are mainly two ways to have a test-suite handle multiple device-types, and orientations. The easy way: Run your test-suite multiple times on multiple devices, simulators, and orientations.

The hard way: Mock and Stub your way to multi-device support in one single test-suite.

#### Device Fakes

Like a lot of things, this used to be easier in simpler times. When you could just set a device size, and go from there, you can see this in Eigen's - ARTestContext.m

TODO - Link ^

``` objc
static OCMockObject *ARPartialScreenMock;

@interface UIScreen (Prvate)
- (CGRect)_applicationFrameForInterfaceOrientation:(long long)arg1 usingStatusbarHeight:(double)arg2 ignoreStatusBar:(BOOL)ignore;
@end

+ (void)runAsDevice:(enum ARDeviceType)device
{
[... setup]

ARPartialScreenMock = [OCMockObject partialMockForObject:UIScreen.mainScreen];
NSValue *phoneSize = [NSValue valueWithCGRect:(CGRect)CGRectMake(0, 0, size.width, size.height)];

[[[ARPartialScreenMock stub] andReturnValue:phoneSize] bounds];
[[[[ARPartialScreenMock stub] andReturnValue:phoneSize] ignoringNonObjectArgs] _applicationFrameForInterfaceOrientation:0 usingStatusbarHeight:0 ignoreStatusBar:NO];
}
```
This ensures all ViewControllers are created at the expected size. Then you can use your own logic to determine iPhone vs iPad. This works for simple cases, but it isn't optimal in the current landscape of iOS apps.
#### Trait Fakes
Trait collections are now the recommended way to distinguish devices, as an iPad could now be showing your app in a screen the size of an iPhone. You can't rely on having an application the same size as the screen. This makes it more complex. 🎉
This is not a space I've devoted a lot of time to, so consider this section a beta. If anyone wants to dig in, I'd be interested in knowing what the central point of knowledge for train collections is, and stubbing that in the way I did with `_applicationFrameForInterfaceOrientation:usingStatusbarHeight:ignoreStatusBar:`.
Every View or View Controller (V/VC) has a read-only collection of traits, the V/VCs can listen for trait changes and re-arrange themselves. For example, we have a view that sets itself up on the collection change:
TODO: Link to AuctionBannerView.swift
``` swift
class AuctionBannerView: UIView {
override func traitCollectionDidChange(previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
// Remove all subviews and call setupViews() again to start from scratch.
subviews.forEach { $0.removeFromSuperview() }
setupViews()
}
}
```

When we test this view we stub the `traitCollection` array and trigger `traitCollectionDidChange`, this is done in our [Forgeries](https://github.com/ashfurrow/forgeries) library. It looks pretty much like this, with the environment being the V/VC.

``` objc
void stubTraitCollectionInEnvironment(UITraitCollection *traitCollection, id<UITraitEnvironment> environment) {
id partialMock = [OCMockObject partialMockForObject:environment];
[[[partialMock stub] andReturn:traitCollection] traitCollection];
[environment traitCollectionDidChange:nil];
}
```
Giving us the chance to make our V/VC think it's in any type of environment that we want to write tests for.
6 changes: 3 additions & 3 deletions chapters/en-UK/app_testing/views__snapshots.md
@@ -1,4 +1,4 @@
### Snapshot Testing
## Snapshot Testing

The process of taking a snapshot of the view hierarchy of a UIView subclass, then storing that as a reference for what your app should look like.

Expand All @@ -13,10 +13,10 @@ We aim for snapshot tests to cover two main areas
1. Overall state for View Controllers
2. Individual States per View Component

As snapshots are the largest testing brush, and as the apps I work on tend to be fancy perspectives on remote data. Snapshot testing provides easy coverage,
As snapshots are the largest testing brush, and as the apps I work on tend to be fancy perspectives on remote data. Snapshot testing provides easy coverage, for larger complex objects like view controllers


### Got-chas with Testing View Controllers
### Common issues with Testing View Controllers

Turns out to really grok why some problems happen you have to have quite a solid foundation in:

Expand Down
2 changes: 1 addition & 1 deletion chapters/en-UK/foundations/stubs_mocks_and_fakes.md
Expand Up @@ -20,7 +20,7 @@ From a personal opinion I avoid stubbing and mocking code which is under my cont

When you first get started, using Mocks and Stubs feel like the perfect tool for testing code, but it becomes unwieldy as it can quickly get out of sync with reality. They can be a great crutch, when you really can't figure out how to test something however.

A great example of when to use stubbing is when dealing with an Apple class that you cannot easily replace or use your own copy. For example I regularly use partial mocks of `UIScreen` instances in order to emulate being on an iPad simulator when it's actually running on an iPhone simulator. This saves us time from running our test suite twice, sequentially, on multiple simulators.
A great example of when to use stubbing is when dealing with an Apple class that you cannot easily replace or use your own copy. For example I regularly use partial mocks of `UIScreen` instances in order to emulate being on an iPad simulator when it's actually running on an iPhone simulator. This saves us time from running our test-suite twice, sequentially, on multiple simulators.

When you own the code that you're working with, it can often be easier to use a fake.

Expand Down

0 comments on commit 780538e

Please sign in to comment.