I'm developing an Webapp. It consists of 2 parts. A node rest server and an angularjs client.
The app is structured this way: Rest Server <--> Api Module <--> Angular App
The server is currently well tested. I have Unit Tests and Integration Tests. The Integration Tests are accessing a real database and calling the rest api over http. I think this is as high level as it can get for the server testing. The integration tests run fast, too. I'm pretty confident that the way I tested the server is sufficient for my use case and I'm happy with the results.
However I'm struggling how to test the angularjs app. I have unit tests for the relevant directives and modules. Writing these wasn't an issue.
I would like to write integration tests that cover user scenarios. Something like a signup scenario: The user visits the website, goes to the signup form, and submits the form with the data.
The angularjs team is moving from ng-scenarios to protractor. Protractor is using Selenium to run the tests. Therefore there are two scopes: The app scope and the test scope.
Now I can think of three different abstractions I could use. And I'm not sure which one suites me best.
- Mock the Api Module
- Mock the Rest Server
- Use the full server
Mock the Api Module
In this case I would need not to setup a server. All Interactions are running in the browser
Advantage:
- No server is needed
Disadvantage:
- The api is in the browser scope and I have to tamper with this.
I really like this solution, but I find it difficult to mock the Api.
The Api needs to be modified in the browsers scope.
Therefore I need to send the modification from the test to the browser.
This can be done, however I don't see how I could run assertions like mockedApi.method.wasCalledOnce()
in the tests scope
Mock the Rest Server
Advantage:
- Client would be unchanged
- Only one scope to deal with
Disadvantage:
- One has to setup the Rest Routes
I could create a complete Mock Rest Server in nodejs.
Protractor Tests are written in nodejs, thus the control of the server can be done in the test.
Before I run the test I can tell the server how to respond.
Something like this: server.onRequest({method: 'GET', url: '/'}).respondWith('hello world')
Then I could do assertions like wasCalledOnce
Use the full Server with Database
Each test is running with a complete server and can add elements to the database. After each test one can look at the expected elements in the database
Advantage:
- Can be pretty sure, that if these tests are running the app is functional in the tested use case
Disadvantage:
- I already made a fairly intense integration test with the rest server. This feels like doing the same again.
- Setup depends on the full server
Current Conclusion
- Mocking the Api would separate the server and the client completely.
- Using a Mock Api would be a higher level test, but would require a fake server
- Doing a full integration test would give the best reliability, but this is also highly dependant on the server code
What should I pick? What would you do?