Skip to content

Commit

Permalink
Merge pull request #67 from andrzejchm/develop
Browse files Browse the repository at this point in the history
0.2.2 release
  • Loading branch information
andrzejchm authored Jun 24, 2017
2 parents 19c0f61 + b9d144b commit 7842d6b
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 62 deletions.
37 changes: 19 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
[![Android Arsenal](https://img.shields.io/badge/Android%20Arsenal-RESTMock-green.svg?style=true)](https://android-arsenal.com/details/1/3468) [![Circle CI](https://circleci.com/gh/andrzejchm/RESTMock.svg?style=svg)](https://circleci.com/gh/andrzejchm/RESTMock)

REST API mocking made easy.
##About

## About
RESTMock is a library working on top of Square's [okhttp/MockWebServer](https://github.com/square/okhttp/tree/master/mockwebserver). It allows you to specify [Hamcrest](https://github.com/hamcrest/JavaHamcrest) matchers to match HTTP requests and specify what response to return. It is as easy as:

```java
Expand All @@ -13,7 +14,7 @@ RESTMockServer.whenGET(pathContains("users/defunkt"))
**Article**
- [ITDD - Instrumentation TDD for Android](https://medium.com/@andrzejchm/ittd-instrumentation-ttd-for-android-4894cbb82d37)

##Table of Contents
## Table of Contents
- [About](#about)
- [Setup](#setup)
- [Request verification](#request-verification)
Expand All @@ -25,7 +26,7 @@ RESTMockServer.whenGET(pathContains("users/defunkt"))
## Setup
Here are the basic rules to set up RESTMock for Android

####Step 1: Repository
#### Step 1: Repository
Add it in your root build.gradle at the end of repositories:

```groovy
Expand All @@ -36,16 +37,16 @@ allprojects {
}
}
```
####Step 2: Dependencies
#### Step 2: Dependencies
Add the dependency

```groovy
dependencies {
androidTestCompile 'com.github.andrzejchm.RESTMock:android:0.2.1'
androidTestCompile 'com.github.andrzejchm.RESTMock:android:0.2.2'
}
```

####Step 3: Start the server
#### Step 3: Start the server
It's good to start server before the tested application starts, there are few methods:

##### a) RESTMockTestRunner
Expand Down Expand Up @@ -75,9 +76,9 @@ public class MyAppTestRunner extends AndroidJUnitRunner {
```


####Step 4: Specify Mocks
#### Step 4: Specify Mocks

#####a) Files
##### a) Files
By default, the `RESTMockTestRunner` uses `AndroidAssetsFileParser` as a mocks file parser, which reads the files from the assets folder. To make them visible for the RESTMock you have to put them in the correct folder in your project, for example:

.../src/androidTest/assets/users/defunkt.json
Expand All @@ -88,23 +89,23 @@ RESTMockServer.whenGET(pathContains("users/defunkt"))
.thenReturnFile(200, "users/defunkt.json");
```

#####b) Strings
##### b) Strings
If the response You wish to return is simple, you can just specify a string:

```java
RESTMockServer.whenGET(pathContains("users/defunkt"))
.thenReturnString(200, "{}");
```
#####c) MockResponse
##### c) MockResponse
If you wish to have a greater control over the response, you can pass the `MockResponse`
```java
RESTMockServer.whenGET(pathContains("users/defunkt")).thenReturn(new MockResponse().setBody("").setResponseCode(401).addHeader("Header","Value"));
```

####Step 5: Request Matchers
#### Step 5: Request Matchers
You can either use some of the predefined matchers from `RequestMatchers` util class, or create your own. remember to extend from `RequestMatcher`

####Step 6: Specify API Endpoint
#### Step 6: Specify API Endpoint
The most important step, in order for your app to communicate with the testServer, you have to specify it as an endpoint for all your API calls. For that, you can use the ` RESTMockServer.getUrl()`. If you use Retrofit, it is as easy as:

```java
Expand All @@ -114,7 +115,7 @@ RestAdapter adapter = new RestAdapter.Builder()
.build();
```

##Response chains
## Response chains
You can chain different responses for a single request matcher, all the `thenReturn*()` methods accept varags parameter with response, or you can call those methods multiple times on a single matcher, examples:

```java
Expand All @@ -131,7 +132,7 @@ RESTMockServer.whenGET(pathEndsWith(path))
.thenReturnString("a single call", "answer no 2", "answer no 3");
```

##Response delays
## Response delays
Delaying responses is accomplished with the `delay(TimeUnit timeUnit, long delay)` method. Delays can be specified in chain, just like chaining responses:

```java
Expand All @@ -152,7 +153,7 @@ RESTMockServer.whenGET(pathEndsWith(path))

Which will result in 1st response being delayed by 5 seconds, 2nd response by 10 seconds and 3rd, 4th, 5th... by 15 seconds.

####Interleaving delays with responses
#### Interleaving delays with responses
Check out this example:

```java
Expand All @@ -167,7 +168,7 @@ RESTMockServer.whenGET(pathEndsWith(path))
```
this will result in `1st call` being delayed by 5 seconds, `2nd call` delayed by 10 seconds, `3rd call` delayed by 15 seconds, another one by 20 seconds, and another by 30 seconds, and then every consecutive response with 40 seconds delay

##Request verification
## Request verification
It is possible to verify which requests were called and how many times thanks to `RequestsVerifier`. All you have to do is call one of these:

```java
Expand Down Expand Up @@ -197,7 +198,7 @@ RequestsVerifier.takeFirst(5);
RequestsVerifier.takeAllMatching(isGET());
```

##Logging
## Logging
RESTMock supports logging events. You just have to provide the RESTMock with the implementation of `RESTMockLogger`. For Android there is an `AndroidLogger` implemented already. All you have to do is use the `RESTMockTestRunner` or call

```java
Expand Down Expand Up @@ -231,7 +232,7 @@ using `RuntimeEnvironment.application` from within a Robolectric test.
## Android Sample Project
You can check out the sample Android app with tests [here](androidsample/)

##License
## License

Copyright (C) 2016 Appflate.io

Expand Down
8 changes: 3 additions & 5 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,12 @@ apply from: '../quality_tools/findbugs.gradle'
group = 'com.github.andrzejchm'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
compileSdkVersion 26
buildToolsVersion "25.0.3"

defaultConfig {
minSdkVersion 10
targetSdkVersion 25
versionCode 1
versionName "1.0"
targetSdkVersion 26
}
buildTypes {
release {
Expand Down
11 changes: 5 additions & 6 deletions androidsample/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,13 @@ apply plugin: 'android-apt'
apply from: '../quality_tools/findbugs.gradle'

android {
compileSdkVersion 25
buildToolsVersion "25.0.2"
compileSdkVersion 26
buildToolsVersion "25.0.3"

defaultConfig {
applicationId "io.appflate.restmock.androidsample"
minSdkVersion 10
targetSdkVersion 25
minSdkVersion 14
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner 'io.appflate.restmock.androidsample.CustomTestRunner'
Expand All @@ -58,7 +58,6 @@ android {
configurations.all {
resolutionStrategy {
force "com.android.support:support-annotations:${supportLibraryVersion}"
force 'com.squareup.okio:okio:1.8.0'
force "com.squareup.okhttp3:okhttp:${okHttpVersion}"
}
}
Expand Down Expand Up @@ -103,7 +102,7 @@ dependencies {
exclude module: 'recyclerview-v7'
}
testCompile "org.robolectric:robolectric:3.2.2"

testCompile project(':android')
testCompile 'org.khronos:opengl-api:gl1.1-android-2.1_r1' //required to resolve robolectric test problems
testCompile(project(':core')) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,7 @@
import io.appflate.restmock.RequestsVerifier;
import io.appflate.restmock.androidsample.pageobjects.MainActivityPageObject;
import io.appflate.restmock.androidsample.view.activities.MainActivity;
import io.appflate.restmock.utils.RequestMatchers;

import static io.appflate.restmock.RequestsVerifier.verifyRequest;
import static io.appflate.restmock.utils.RequestMatchers.pathEndsWith;

/**
Expand All @@ -41,7 +39,8 @@ public class MainActivityTest {
private static final String NAME_ANDRZEJ_CHMIELEWSKI = "RESTMock: Andrzej Chmielewski";
private static final String PATH_USER_NOT_FOUND = "mocks/users/user_not_found.json";
private static final String REPOS = "/repos";
@Rule public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(
@Rule
public ActivityTestRule<MainActivity> rule = new ActivityTestRule<>(
MainActivity.class,
true,
false);
Expand All @@ -68,8 +67,7 @@ public void testGoodAnswer() throws Exception {

@Test
public void testNotFound() throws Exception {
RESTMockServer.whenGET(pathEndsWith(USERNAME_ANDRZEJCHM)).thenReturnFile(404,
PATH_USER_NOT_FOUND);
RESTMockServer.whenGET(pathEndsWith(USERNAME_ANDRZEJCHM)).thenReturnFile(404, PATH_USER_NOT_FOUND);
//launches activity with default intent
rule.launchActivity(null);
pageObject.typeUsername(USERNAME_ANDRZEJCHM);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2016 Scott Johnson, jaywir3@gmail.com
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package io.appflate.restmock.androidsample.junit;

import org.junit.Before;
import org.junit.Test;
import org.robolectric.Robolectric;

import java.util.List;

import javax.inject.Inject;

import io.appflate.restmock.JVMFileParser;
import io.appflate.restmock.RESTMockServer;
import io.appflate.restmock.RESTMockServerStarter;
import io.appflate.restmock.androidsample.domain.GithubApi;
import io.appflate.restmock.androidsample.model.Repository;
import io.appflate.restmock.androidsample.model.User;
import retrofit2.Response;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

import static io.appflate.restmock.utils.RequestMatchers.pathEndsWith;
import static junit.framework.Assert.assertEquals;

public class JUnitExampleTest {

public static final String USERNAME_JWIR3 = "jwir3";
public static final String PATH_JWIR3_PROFILE = "users/jwir3/profile.json";
public static final String PATH_JWIR3_REPOS = "users/jwir3/repos.json";
private static final String PATH_USER_NOT_FOUND = "users/user_not_found.json";
private static final String REPOS = "/repos";

// Data about my github profile to check against.
public static final String JWIR3_NAME = "Scott Johnson";
public static final String JWIR3_COMPANY = "Aperture Science";
public static final String JWIR3_BLOG = "www.jwir3.com";
public static final String JWIR3_LOCATION = "Burnsville, MN, USA";
public static final String JWIR3_EMAIL = "jaywir3@gmail.com";

@Inject
GithubApi api;

@Before
public void setUp() {
// Be sure to reset the server before each test
RESTMockServerStarter.startSync(new JVMFileParser());
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(RESTMockServer.getUrl())
.addConverterFactory(GsonConverterFactory.create())
.build();

api = retrofit.create(GithubApi.class);
}

@Test
public void testValidUser() throws Exception {
RESTMockServer.whenGET(pathEndsWith(USERNAME_JWIR3)).thenReturnFile(200, PATH_JWIR3_PROFILE);

// Note: This is not recommended in non-test code, since this is a blocking call.
// TODO: Use RxJava magic here to make this easier to show how to accomplish asynchronously.
Response<User> response = api.getUserProfile(USERNAME_JWIR3).execute();
assertEquals(200, response.code());

User jwir3 = response.body();
assertEquals(JWIR3_NAME, jwir3.name);
assertEquals(JWIR3_BLOG, jwir3.blog);
assertEquals(JWIR3_COMPANY, jwir3.company);
assertEquals(JWIR3_EMAIL, jwir3.email);
assertEquals(JWIR3_LOCATION, jwir3.location);
}

@Test
public void testNotFound() throws Exception {
RESTMockServer.whenGET(pathEndsWith(USERNAME_JWIR3)).thenReturnFile(404, PATH_USER_NOT_FOUND);

// Note: This is not recommended in non-test code, since this is a blocking call.
// TODO: Use RxJava magic here to make this easier to show how to accomplish asynchronously.
Response<User> res = api.getUserProfile(USERNAME_JWIR3).execute();
assertEquals(404, res.code());
}

@Test
public void testShowRepos() throws Exception {
RESTMockServer.whenGET(pathEndsWith(REPOS)).thenReturnFile(200, PATH_JWIR3_REPOS);

// Note: This is not recommended in non-test code, since this is a blocking call.
// TODO: Use RxJava magic here to make this easier to show how to accomplish asynchronously.
Response<List<Repository>> res = api.getUserRepos(USERNAME_JWIR3).execute();
assertEquals(200, res.code());

List<Repository> repos = res.body();
assertEquals(29, repos.size());
}
}
5 changes: 3 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.2.0'
classpath 'com.android.tools.build:gradle:2.3.2'
classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'

// NOTE: Do not place your application dependencies here; they belong
Expand All @@ -33,8 +33,9 @@ allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
maven { url "https://maven.google.com" }
}
version = "0.2.1"
version = "0.2.2"
}

ext.preDexLibraries = project.hasProperty('preDexLibraries')
Expand Down
6 changes: 3 additions & 3 deletions circle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ machine:
## Customize dependencies
dependencies:
pre:
- echo y | android update sdk --no-ui --all --filter "tools,build-tools-24,platform-tools"
- echo y | android update sdk --no-ui --all --filter "android-25"
- echo y | android update sdk --no-ui --all --filter "build-tools-25.0.2"
- echo y | android update sdk --no-ui --all --filter "tools,build-tools-25,platform-tools"
- echo y | android update sdk --no-ui --all --filter "android-26"
- echo y | android update sdk --no-ui --all --filter "build-tools-25.0.3"
- echo y | android update sdk --no-ui --all --filter "platform-tools-preview"
- echo y | android update sdk --no-ui --all --filter "build-tools-25,extra-google-m2repository,xtra-android-support,extra-android-m2repository"
## Customize test commands
Expand Down
Loading

0 comments on commit 7842d6b

Please sign in to comment.