Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Test Environment with Mocked REST API

Tags:

python

rest

Lets say I have a very simple web app which is presented as blue if the current president is a democrat and red if they are a republican. A REST API is used to get the current president, via the endpoint:

/presidents/current

which currently returns the json object:

{name: "Donald Trump", party: "Republican"}

So when my page loads I call the endpoint and I show red or blue depending on who is returned.

I wish to test this HTML/javascript page and I wish to mock the back-end so that I can control from within the test environment the API responses. For example:

def test_republican():
    # configure the response for this test that the web app will receive when it connects to this endpoint
    configure_endpoint(
        "/presidents/current", 
        jsonify(
            name="Donald Trump",
            party="Republican"
        )
    )  

    # start the web app in the browser using selenium 
    load_web_app(driver, "http://localhost:8080")  

    e = driver.find_element_by_name("background")
    assert(e.getCssValue("background-color") == "red")


def test_democrat():
    # configure the response for this test that the web app will receive when it connects to this endpoint
    configure_endpoint(
        "/presidents/current", 
        jsonify(
            name="Barack Obama",
            party="Democrat"
        )
    )    

    # start the web app in the browser using selenium 
    load_web_app(driver, "http://localhost:8080")  

    e = driver.find_element_by_name("background")
    assert(e.getCssValue("background-color") == "blue")

So the question is how should I implement the function configure_endpoint() and what libraries can you recommend me?

like image 939
Baz Avatar asked Jan 26 '17 23:01

Baz


People also ask

How do I use mock REST API?

Right-click on the project and select New REST MockService from the menu. Right-click on the Mock Service and select Add new mock action from the menu. Select the HTTP method and give the resource path, it can be anything. I have selected GET method and my resource path is test .

What does mocking API mean?

A mock API server or mock server API imitates a real API server by providing realistic mock API responses to requests. They can be on your local machine or the public Internet. Responses can be static or dynamic, and simulate the data the real API would return, matching the schema with data types, objects, and arrays.


1 Answers

As @Kie mentioned, configure_endpoint implementation won't be enough, if you're going to stub the whole server-side within Selenium Python code. You would need a web server or whatever that will response via HTTP to requests from within testing environment.

It looks like the question is partially about testing of client-side code. What I see is that you're trying to make unit-test for client-side logic, but use integration testing suite in order to check this logic (it's strange).

The main idea is as follows.

You're trying to test client-side code. So, let's make mocks client-side too! Because this part of code is completely client-side related stuff.

If you actually want to have mocks, not stubs (watch the difference here: https://stackoverflow.com/a/3459491/882187) it is a better way to mock out HTTP requests inside your Javascript code. Just because you're testing a client-side piece of code, not some parts of server-side logic.

Having it isolated from whatever server-side is - is a great idea that you would love when your project become grow, while more and more endpoints will be appearing.

For example, you can use the following approach:

var restResponder = function() { // the original responder your client-side app will use
  this.getCurrentPresident = function(successCallback) {
    $.get('/presidents/current', callback);
  }
};

var createMockResponder = function(president, party){ // factory that creates mocks
  var myPresident = president;
  var myParty = party;

  return function() {
    this.getCurrentPresident = function (successCallback) {
      successCallback({"name": myPresident, "party": myParty});
    }
  };
}

// somewhere swap the original restResponder with new mockResponder created by 'createMockResponder'

// then use it in your app:

function drawColor(restResponder, backgroundEl) {
  restResponder.getCurrentPresident(function(data){
     if (data.party == "Democrat") $(backgroundEl).style('background-color', 'blue')
     else if (data.party == "Republican") $(backgroundEl).style('background-color', 'red')
     else console.info('Some strange response from server... Nevermind...');
  });
}

Practically, this implementation depends on what do you have at the client-side as a framework. If jQuery, then my example is enough, but it looks very wordy. In case you have something more advanced, like AngularJS, you can do the same in 2-3 lines of code:

// Set up the mock http service responses
$httpBackend = $injector.get('$httpBackend');
// backend definition common for all tests
authRequestHandler = $httpBackend.when('GET', '/auth.py')
                                 .respond({userId: 'userX'}, {'A-Token': 'xxx'});

Check out the docs: https://docs.angularjs.org/api/ngMock/service/$httpBackend

If you're still stick to the idea, that you need mocks inside Selenium tests, please try this project: https://turq.readthedocs.io/en/latest/

It serves with Python DSL for describing REST responders. Using turq your mocks will look as follows:

path('/presidents/current').json({'name':'Barack Obama', 'party': 'Democrat'}, jsonp=False)

Also, I would recommend to try stubs instead of mocks and use this Python module: mock-server https://pypi.python.org/pypi/mock-server/0.3.7 You are required to create the directory layout containing corresponding pre-populated JSON responses and to add some boilerplate code in order to make the mock-server respond on 'localhost:8080'. The directory layout for your example will look like this:

stub_obama/
  presidents/
    current/
      GET_200.json      # will contain {"name": "Barack Obama", "party": "Democrat"}
stub_trump/
  presidents/
    current/
      GET_200.json      # will contain {"name": "Donald Trump", "party": "Republican"}

But the mock_server is based on Tornado, it is very heavy solution for using in tests I think.

I hope, my answer is helpful and informative. Welcome to discuss it! I made tons of projects with Selenium, big and small tests, tested client-side and server-side.

like image 176
Vladimir Ignatyev Avatar answered Oct 11 '22 12:10

Vladimir Ignatyev