{"id":2086,"url":"https://github.com/Skyscanner/Dixie","last_synced_at":"2025-08-02T23:32:01.504Z","repository":{"id":56908605,"uuid":"37461780","full_name":"Skyscanner/Dixie","owner":"Skyscanner","description":"Dixie, turning chaos to your advantage.","archived":true,"fork":false,"pushed_at":"2015-12-10T10:47:31.000Z","size":4534,"stargazers_count":191,"open_issues_count":0,"forks_count":4,"subscribers_count":54,"default_branch":"master","last_synced_at":"2024-11-10T16:53:24.714Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://skyscanner.github.io/Dixie/","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Skyscanner.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-06-15T11:45:49.000Z","updated_at":"2024-10-04T19:54:28.000Z","dependencies_parsed_at":"2022-08-21T03:50:22.319Z","dependency_job_id":null,"html_url":"https://github.com/Skyscanner/Dixie","commit_stats":null,"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyscanner%2FDixie","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyscanner%2FDixie/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyscanner%2FDixie/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Skyscanner%2FDixie/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Skyscanner","download_url":"https://codeload.github.com/Skyscanner/Dixie/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":228503132,"owners_count":17930517,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:16:03.160Z","updated_at":"2024-12-06T17:30:45.846Z","avatar_url":"https://github.com/Skyscanner.png","language":"Objective-C","funding_links":[],"categories":["Testing"],"sub_categories":["TDD / BDD","Other free courses"],"readme":"Dixie\n===\n\u003cimg src=\"/Logo.png?raw=true\" alt=\"Dixie\" width=\"100px\" height=\"auto\"\u003e\n\nDixie is an open source Objective-C testing framework for altering object behaviours. Test your app through creating chaos in the inner systems. The primary goal of Dixie is to provide a set of tools, which the developers can test their code with. Behind the goal is the ideology of _\"do not always expect the best\"_. You can read more about this [here](https://medium.com/@Skyscanner/dixie-turning-chaos-to-your-advantage-4f3749e6d485).\n\n[![Build Status](https://travis-ci.org/Skyscanner/Dixie.svg)](https://travis-ci.org/Skyscanner/Dixie)\n\n### How can you test your application with Dixie\n1. Create a new target in your app’s project that runs your Dixie setup logic during app launch. With the separate target you can make sure all Dixie related code is separated and won’t be included in your production builds\n2. Change the behaviour of some components with Dixie and deploy the test build to device or simulator to see how your app behaves\n3. Once you got familiar with the library, it might be worth to create a list of behaviour changes that you can easily configure and combine from your debug build\n\n### A few ideas what you can do\n* Hijack the localisation component of your app to simulate long strings or other unexpected text\n* Inject mocked network responses into the network layer (you can match the URLs with a regular expression so you can provide different responses for different requests)\n* Network mocking can also be utilised in automated UI tests, so you don’t have to rely on real network communication\n* You can easily mock GPS coordinates or even the current date, so you do not have to set the simulators location manually\n* Inject randomised properties to your data models to see how robust is your application handling the objects received from web\n\n### In our projects we use Dixie in two ways\n\n1. We just put the Dixie configuration code in the `AppDelegate` and remove if not needed (these are short testing sessions). `#ifdef`-ing is an option, also creating a separate target that has a category on the `AppDelegate`.\n2. We use Dixie in the automated UI tests as a standard mocking framework. The tests rely on the final app target, and we found extremely hard to mock components on the low level (e.g. networking) in this scope.\n\nEither way we think Dixie comes handy in cases, where you have to mock libraries, that's less configurable or some components are not that easily injectable.\n\n\n\n## Installation\n#### With CocoaPods\n[CocoaPods](https://cocoapods.org) is the recommended way to add Dixie to your project.\n\n- Add Dixie to your Podfile\n\n\t`pod 'Dixie'`\n- Install/update pod(s)\n\n\t`pod install`\n\n- Include DixieHeaders.h where you would like to use Dixie\n\n\t`#import \u003cDixieHeaders.h\u003e`\n\n#### Without CocoaPods\nYou can add Dixie without CocoaPods to your project if you download the Dixie project and add it manually to your project. Don't forget to add the project path into the Header Search Path.\n\nYou can see an example for this integration in the [Example app](https://github.com/Skyscanner/Dixie#example-app)\n\n\n\n\n##Usage\nFirst define which method on which class the change should be applied to, and its new behaviour. You can do this by creating a `DixieProfileEntry`:\n\n```objective-c\n//Tomorrow\nNSDate* testDate = [NSDate dateWithTimeIntervalSinceNow:24*60*60];\n\n//A behaviour to always return tomorrow's date\nDixieChaosProvider* provider = [DixieConstantChaosProvider constant:testDate];\n\n//Create the entry\nDixieProfileEntry* entry = [DixieProfileEntry entry:[NSDate class] selector:@selector(date) chaosProvider:provider]\n```\n\t\nThen create an instance of a `Dixie` configuration, set the profile and apply.\n\n```objective-c\n//Create Dixie configuration\nDixie* dixie = [Dixie new];\n\t\n//Set and apply change\ndixie\n\t.Profile(entry)\n\t.Apply();\n```\n\nAfter applying the profile, every call of `[NSDate date]` will return the date for tomorrow instead of today. This way you can test date issues without going to the device settings and changing the date manually.\n\nWhen you no longer need Dixie, revert your change:\n\n```objective-c\n//Revert the change of the entry\ndixie\n\t.RevertIt(entry);\n```\n\nFull code:\n\n```objective-c\n- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions\n{\n\tNSDate* testDate = [NSDate dateWithTimeIntervalSinceNow:24*60*60];\n\n\tDixieChaosProvider* provider = [DixieConstantChaosProvider constant:testDate];\n\t\n\tDixieProfileEntry* entry = [DixieProfileEntry entry:[NSDate class] selector:@selector(date) chaosProvider:provider]\n\t\t\n\tDixie* dixie = [Dixie new];\n\n\tdixie\n\t\t.Profile(entry)\n\t\t.Apply();\n\t\n\treturn YES;\t\n}\n```\n\nYou can set multiple profiles and also revert them all at once. You can also choose from some preset behaviours:\n\n####DixieNonChaosProvider\nProvides the original behaviour. Good to use when you want to have a different behaviour in special cases only.\n\n####DixieConstantChaosProvider\nProvides a behaviour that always returns a constant object.\n\n####DixieNilChaosProvider\nProvides a behaviour that always returns `nil`.\n\n####DixieBlockChaosProvider\nProvides a behaviour that is described by a block. Using this provider the method can be replaced with a full custom behaviour. For accessing method parameters and setting the return value you can use the `DixieCallEnvironment` object passed to the block.\n\n####DixieRandomChaosProvider\nProvides a behaviour that returns a random object. The default implementation returns a random `NSNumber`.\n\n####DixieExceptionChaosProvider\nProvides a behaviour that throws an exception.\n\n####DixieSequentialChaosProvider\nFor every call it returns the _ith_ chaosprovider's behaviour, where `i` is the number of the call. If the number of calls exceeds the number of predefined chaosprovider the last provider's behaviour will be used.\n\n####DixieCompositeChaosProvider\nChecks the parameters of the method and if one matches the value of a given `DixieCompositeCondition`, then it returns the connected chaosprovider's behaviour.\n\n# Under the hood\nThe idea of changing an object's behaviour is not new. It is usually used in unit testing, where a component's dependencies are mocked to have a controlled, reproducible environment. In these situations there is the requirement that the target project should be _easily injectable_. If you are depending on components that are not made by you, or that are not injectable, you have to turn to different methods. To implement the theory of creating chaos/altering component behaviour in Objective-C environment, Dixie uses the technique of _Method Swizzling_. Method swizzling relies on calling special runtime methods, that require knowing the target method and its environment. Dixie takes care of handling the runtime for you, and also hides the original method environment, so you only have to focus on defining the new behaviour and can apply it quickly and simply.\n\n__Note:__ \n* The current implementation is best at changing behaviours of methods on iOS simulator. Support for arm architectures will come in the next version.\n* Dixie is best for testing so, as with other similar libraries, its usage in production environments is strongly discouraged.\n\n\n# Example app\nYou can find a [Dixie example app project](https://github.com/Skyscanner/Dixie/tree/master/DixieExampleApp) in the repository with some common use-cases of how to use Dixie. The project requires [CocoaPods](https://cocoapods.org) dependency manager, so you have to run the `pod install` command in the `DixieExampleApp` directory before you can run the project.\n\nThe example app covers three use-cases:\n\n#### Location mocking\nShows the actual location on a map using the [`CLLocationManager`](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManager_Class/index.html). Dixie changes the implementation of the [`locationManager:didUpdateLocations:`](https://developer.apple.com/library/ios/documentation/CoreLocation/Reference/CLLocationManagerDelegate_Protocol/#//apple_ref/occ/intfm/CLLocationManagerDelegate/locationManager:didUpdateLocations:) method, so any location can be mocked easily. The example app mocks a random city. With Dixie Revert function the device location is used. The whole logic can be found in the [`MapViewController.m`](https://github.com/Skyscanner/Dixie/blob/master/DixieExampleApp/DixieExampleApp/MapViewController.m). It uses a `DixieBlockChaosProvider` to be able to change the method implementation with a block.\n\n#### Date mocking\nA countdown timer to the next [Halley's Comet](http://en.wikipedia.org/wiki/Halley's_Comet) arrival. The countdown timer uses the actual date function ([`[NSDate date]`](https://developer.apple.com/library/ios/documentation/Cocoa/Reference/Foundation/Classes/NSDate_Class/#//apple_ref/occ/clm/NSDate/date)) and Dixie changes the implementation of this method and mocks a random date between -10000 and +10000 days from the actual date. The whole logic can be found in the [`CountDownViewController.m`](https://github.com/Skyscanner/Dixie/blob/master/DixieExampleApp/DixieExampleApp/CountDownViewController.m). It uses a `DixieConstantChaosProvider` which provides a constant value mocking.\n\n#### Network mocking\nThis example shows the weather at the actual location using [OpenWeatherMap API](http://openweathermap.org/api) as the data source and [AFNetworking](https://github.com/AFNetworking/AFNetworking) which is a popular iOS and OS X networking framework. Dixie changes the implementation of the `GET:parameters:success:failure:` method implementation of the [`AFHTTPRequestOperationManager`](https://github.com/AFNetworking/AFNetworking/blob/7f997ef99ae64e321b6747defcaae5b13a691119/AFNetworking/AFHTTPRequestOperationManager.h) class of the `AFNetworking` framework. The request is not going out to the network, Dixie creates the response object and calls the `success` callback which is the async callback coming from a successful network response. The whole logic can be found in the [`WeatherViewController.m`](https://github.com/Skyscanner/Dixie/blob/master/DixieExampleApp/DixieExampleApp/WeatherViewController.m), it uses a `DixieBlockChaosProvider`.\n\n\n#About\nThe Dixie was born from the idea of Peter Adam Wiesner. The prototype was brought to life by Phillip Wheatley, Tamas Flamich, Zsolt Varnai and Peter Adam Wiesner within a research lab project in one week. The prototype was developed into this open source library by Zsolt Varnai, Csaba Szabo, Zsombor Fuszenecker and Peter Adam Wiesner.\n\nIf you know a way to make Dixie better, please contribute!\n\nYou can reach us:\n\n* [peter.wiesner@skyscanner.net](peter.wiesner@skyscanner.net) or  [@Peteee24](https://twitter.com/peteee24)\n* [zsolt.varnai@skyscanner.net](zsolt.varnai@skyscanner.net)\n* [csaba.szabo@skyscanner.net](csaba.szabo@skyscanner.net)\n* [zsombor.fuszenecker@skyscanner.net](zsombor.fuszenecker@skyscanner.net)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSkyscanner%2FDixie","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FSkyscanner%2FDixie","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FSkyscanner%2FDixie/lists"}