Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

This is a public HTTP API to retrieve Twitter user timelines. An example for learning how to test our code in a manner to (i) inject mocks for other modules, (ii) to leak private variables or (iii) override variables within the module.

NotificationsYou must be signed in to change notification settings

igorlima/twitter-rest-api-server

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Gittip Donate Button

JS unit testing using dependency injection

You probably know that to do JavaScript testing is good and some hurdles to overcome is how to test our code in a manner to(i) inject mocks for other modules,(ii) to leak private variables or(iii) override variables within the module.

rewire is a tool for helping us on overcoming these hurdles. It provides us an easy way to dependency injection for unit testing and adds a special setter and getter to modules so we can modify their behaviour for better unit testing. Whatrewire does is to not load the file and eval the contents to emulate the load mechanism.

To get started with dependency injection, we'll createa twitter rest api server and do unit tests using mocks and overriding variables within modules. This example will focus on back-end unit testing but if you want to userewire also on the client-side take a look atclient-side bundlers.

An example

This example is a public HTTP API to retrieve Twitter user timelines. It has basically two files:server.js andtwitter.js.

The first file createsan basic instance ofexpress and definesa route for a GET request method, which is/twitter/timeline/:user.

The second one is a module responsible for retrieving data from Twitter. It requires:

  • twit: Twitter API Client for node
  • async: is a utility module which provides straight-forward, powerful functions for working with asynchronous JavaScript
  • moment: a lightweight JavaScript date library for parsing, validating, manipulating, and formatting dates.

Part of these modules will be mocked and overridden in our tests.

Running the example

This example is already runningin a cloud. So you can reach the urls below and see it working:

To run it locally, clonethis gist bygit clone https://gist.github.com/b31f1a26a5b100186a98.git twitter-rest-api-server and set five environment variables. Those envs are listed below. For secure reason I won't share my token. To get yours, accessTwitter developer documentation,create a new app and set up your credentials.

ForMac users, you can simply type:

export TwitterConsumerKey="xxxx"export TwitterConsumerSecret="xxxx"export TwitterAccessToken="xxxx"export TwitterAccessTokenSecret="xxxx"export MomentLang="pt-br"

ForWindows users, do:

SET TwitterConsumerKey="xxxx"SET TwitterConsumerSecret="xxxx"SET TwitterAccessToken="xxxx"SET TwitterAccessTokenSecret="xxxx"SET MomentLang="pt-br"

After setting up the environment variables, go totwitter-rest-api-server folder, install all node dependencies bynpm install, then run via terminalnode server.js. It should be available at the port5000. Go to your browser and reachhttp://localhost:5000/twitter/timeline/igorribeirolima.

running express app example locally

Writing unit tests

Mocha is the JavaScript test framework running we gonna use. It makes asynchronous testing simple and fun.Mocha allows you to use any assertion library you want, if it throws an error, it will work! In this example we are gonna utilizenode's regular assert module.

Imagine you want to test this codetwitter.js:

varTwit=require('twit'),async=require('async'),moment=require('moment'),T=newTwit({consumer_key:process.env.TwitterConsumerKey||'...',consumer_secret:process.env.TwitterConsumerSecret||'...',access_token:process.env.TwitterAccessToken||'...',access_token_secret:process.env.TwitterAccessTokenSecret||'...'}),mapReducingTweets=function(tweet,callback){callback(null,simplify(tweet));},simplify=function(tweet){vardate=moment(tweet.created_at,"ddd MMM DD HH:mm:ss zz YYYY");date.lang(process.env.MomentLang);return{date:date.format('MMMM Do YYYY, h:mm:ss a'),id:tweet.id,user:{id:tweet.user.id},tweet:tweet.text};};module.exports=function(username,callback){T.get("statuses/user_timeline",{screen_name:username,count:25},function(err,tweets){if(err)callback(err);elseasync.map(tweets,mapReducingTweets,function(err,simplified_tweets){callback(null,simplified_tweets);});})};

To do that in a easy and fun way, let load this module usingrewire. So within your test moduletwitter-spec.js:

varrewire=require('rewire'),assert=require('assert'),twitter=rewire('./twitter.js'),mock=require('./twitter-spec-mock-data.js');

rewire acts exactly likerequire. Just with one difference: Your module will now export a special setter and getter for private variables.

myModule.__set__("path","/dev/null");myModule.__get__("path");// = '/dev/null'

This allows you to mock everything in the top-level scope of the module, like thetwitter module for example. Just pass the variable name as first parameter and your mock as second.

You may also override globals. These changes are only within the module, so you don't have to be concerned that other modules are influenced by your mock.

describe('twitter module',function(){describe('simplify function',function(){varsimplify;before(function(){simplify=twitter.__get__('simplify');});it('should be defined',function(){assert.ok(simplify);});describe('simplify a tweet',function(){vartweet,mock;before(function(){mock=mocks[0];tweet=simplify(mock);});it('should have 4 properties',function(){assert.equal(Object.keys(tweet).length,4);});describe('format dates as `MMMM Do YYYY, h:mm:ss a`',function(){describe('English format',function(){before(function(){revert=twitter.__set__('process.env.MomentLang','en');tweet=simplify(mock);});it('should be `March 6th 2015, 2:29:13 am`',function(){assert.equal(tweet.date,'March 6th 2015, 2:29:13 am');});after(function(){revert();});});describe('Brazilian format',function(){before(function(){revert=twitter.__set__('process.env.MomentLang','pt-br');tweet=simplify(mock);});it('should be `Março 6º 2015, 2:29:13 am`',function(){assert.equal(tweet.date,'Março 6º 2015, 2:29:13 am');});after(function(){revert();});});});});});describe('retrieve timeline feed',function(){varrevert;before(function(){revert=twitter.__set__("T.get",function(api,query,callback){callback(null,mocks);});});describe('igorribeirolima timeline',function(){vartweets;before(function(done){twitter('igorribeirolima',function(err,data){tweets=data;done();});});it('should have 19 tweets',function(){assert.equal(tweets.length,19);});});after(function(){revert();});});});

__set__ returns a function which reverts the changes introduced by this particular__set__ call.

Running unit tests

Before we get into the test and walk through it, let install mocha CLI bynpm install -g mocha. It will support us on running our tests just typingmocha twitter-spec.js. The following is an image that illustrates the test result.

image that ilustrates unit tests running

Take a look on thisvideo and see step by step in detail everything discussed so far.

Conclusion

As you can see it's not painful on overcoming hurdles like(i) injecting mocks for other modules,(ii) leaking private variables or(iii) overriding variables within the module. That's it folks. Hope you catch the idea on how simple and fun is to do dependency injection for unit testing. Thanks for reading.

About

This is a public HTTP API to retrieve Twitter user timelines. An example for learning how to test our code in a manner to (i) inject mocks for other modules, (ii) to leak private variables or (iii) override variables within the module.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

[8]ページ先頭

©2009-2025 Movatter.jp