Giter Site home page Giter Site logo

forgeries's Introduction

Forgeries

Circle CI Forgeries Logo

Forgeries is a library that makes unit testing iOS applications easier. UIKit has lots of limitations that make sense in production code, but make testing difficult. Forgeries fixes that problem.

Usage

Currently, the library provides testing replacements for:

These can be used with Dependency Injection, or by using OCMock to replace global singletons.

Gesture Recognizers

The following are Forgeries' subclasses for gesture recognizers.

  • ForgeryTapGestureRecognizer
  • ForgeryPinchGestureRecognizer
  • ForgeryRotationGestureRecognizer
  • ForgerySwipeGestureRecognizer
  • ForgeryPanGestureRecognizer
  • ForgeryScreenEdgeGestureRecognizer
  • ForgeryLongPressGestureRecognizer

These subclasses keep track of the number of times they've invoked their targets' actions; a handy interface to UIGestureRecognizer is provided:

@interface UIGestureRecognizer (Forgeries)

- (void)invoke;

@end

User Defaults

ForgeriesUserDefaults is a class which is API compatible with NSUserDefaults. It has a few extra tools that make it useful for testing:

  • A quick API [ForgeriesUserDefaults defaults:@{}] for setting up defaults from a dictionary
  • APIs for inspecting the lastSetKey, lastRequestedKey and whether it has been synchronised via hasSyncronised
  • Offers a subscripting interface so you can easily edit the defaults instance
  • Can replace [NSUserDefaults standardUserDefaults] when OCMock is available in the test target

Note this class isn't yet a subclass of NSUserDefaults, and so cannot be DI'd in to Swift classes.

File Manager

ForgeriesFileManager is still new, so it's API is relatively limited as we find more use cases for it.

  • A quick API for setting up defaults from a dictionary

      ForgeriesFileManager *fm = [ForgeriesFileManager withFileStringMap:@{
           @"/docs/EchoTest.json" : @{ @"updated_at" : @"2001-01-23" },
           @"/app/EchoTest.json": @{ @"updated_at" : @"1985-01-23" },
      	 @"/docs/VERSION" : @"1.0.1"
      }];
  • This API will automatically convert dictionaries to raw JSON data, or let you create files with text

  • Uses an in-memory store for file lookup, and accessing data. Faster, and won't change per-developer

  • Is a subclass of NSFileManager, with functions it doesn't support raising exceptions. Help us add more functions.

  • Can replace [NSFileManager defaultManager] when OCMock is available in the test target

Trait Collections

You can stub the trait collections for UIView and UIViewController, the two UITraitEnvironments that we currently support.

[subject stubHorizontalSizeClass:UIUserInterfaceSizeClassRegular];

UIApplication

Nothing to out of the normal here, you can create a ForgeriesApplication which is a UIApplication subclass for DI-ing a test.

Dependency Injection

The trick is to use Forgeries in testing only. A great way to do this is via Dependency Injection. This means injecting a dependency into an instance, instead of having that instance create the dependency itself, or access shared state. Let's take a look at an example.

Say you're testing MyViewController, you'd use lazy loading for your recognizer.

@interface MyViewController ()

@property (nonatomic, strong) UITapGestureRecognizer *recognizer;

@end

@implementation MyViewController

...

- (UITapGestureRecognizer *)recognizer {
	if (_recognizer == nil) {
		_recognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleGestureRecognizer:)];
	}

	return _recognizer;
}

...

What we need to do is set that property before it is lazily loaded. Here's our testing code:

MyViewController *subject = /* Instantiate somehow */
ForgeryTapGestureRecognizer *recognizer = [[ForgeryTapGestureRecognizer alloc] initWithTarget:subject action:@selector(handleGestureRecognizer:)];
subject.recognizer = recognizer;

/* Optionally, set the testing_location and testing_velocity properties on recognizer. */

[recognizer invoke];

expect(subject).to( /* have done something, whatever it is you're testing for */ );

If you're interested in dependency injection, we strongly recommend watching this talk from Jon Reid

Requirements

Requires iOS 7 or higher.

Installation

Forgeries is available through CocoaPods. To install it, simply add the following line to your Podfile under the unit testing target:

target 'MyApp_Tests' do
  inherit! :search_paths

  pod 'Forgeries'
  ...
end

That will import the core functionality, not including mock stuff. If you want to use Forgeries with OCMock, use the following instead:

pod 'Forgeries/Mocks'

Now import the library in your unit tests.

import Forgeries
@import Forgeries;
// or #import <Forgeries/Forgeries.h>

Authors

License

Forgeries is available under the MIT license. See the LICENSE file for more info.

forgeries's People

Contributors

ashfurrow avatar marcelofabri avatar orta avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

forgeries's Issues

Fake UIApplication

https://github.com/orta/energy/blob/314b0d741e8f9b5754284f4ed52f24fb7cfb89bd/ArtsyFolio%20Tests/View%20Controllers/ARLoginViewControllerTests.m#L4-L13

/// Without this, the tests are dependant on if Eigen is installed
@interface FakeApplication : NSObject
@end


@implementation FakeApplication
- (void)setStatusBarHidden:(BOOL)hidden withAnimation:(UIStatusBarAnimation)animation {}
- (BOOL)openURL:(NSURL *)url { return NO; }
- (BOOL)canOpenURL:(NSURL *)url { return NO; }
@end

This one is really simple, but a better version can be built. This is used ATM for checking if app x exists, but can be built do do more.

Add Tests/CI

Testing the gesture recognizer subclasses is very difficult, but the Defaults replacement should be testable.

Add tests and add Travis CI integration.

Project Logo

Everybody knows that every awesome OSS project needs an awesome logo.

I'm thinking maybe the @artsy logo, but with a different font. Or maybe just slightly different kerning.

/cc @orta

Add fake NSFileManager

I think we could do something around the file manager, it's one of the other big non-DI'd singleton in the Foundation space. Eigen could definitely do with this, there's some ugly thing going on in ARFileUtilTests.

Protocol Extension

Instead of using C macros, which are terrible, and adding a category for every class that conforms to UITraitEnvironment, we ought to just use a Swift protocol extension. A friend sent in an example that replicates our existing functionality: https://gist.github.com/asmallteapot/cf91cca4fe692932fac9

This would be way better. The only reason I didn't use this approach is because I tried but Xcode fought back, so I went with C macros (sometimes easier than fighting with Xcode!). But this is better.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.