Advice for the new Tech Lead: The Realities of Distributed Development

This is part of an ongoing blog post series “Advice for the new Tech Lead”.

I want to start by clarifying what I mean by Distributed Development, or at least the flavour that I’m accustomed to. It basically boils down to two teams, internally colocated, but separated from each other in time and space (a bit melodramatic, yes?) by a nontrivial quantity. My experience has mostly involved teams between India and the US/UK, but it’s not hard to substitute other relatively distributed locales.

Let’s face it; not everyone has been there and done that, when it has come to Distributed Development. And if you have, there is a high probability that you were probably in a distributed team, you mostly worked with one group or the other, but not both. Sure, there might have been trips across these groups for short or extended periods of time; but now you’re the Technical Lead, there are some things that you need to consciously start acknowledging. In some cases, embracing some of those discoveries. In many cases, combating their (ugly) implications.

These words I will probably keep repeating in the future, but I’m not apologising for them: Never be Complacent.

Never be Complacent

The inherent characteristic of distributed teams is that there are certain constraints that you, as the tech lead, need to deal with. “Constraints” might seem like a negative term; however, as we’ll see, some constraints can actually be liberating, while others are…well…constraining. So, yeah, let’s get to it.

Time Zones and Empowerment

A team fractures along the weakest seams. Really, almost anything does. In the case of a distributed team, that seam — I mean, those seams — tend to be geography and the circadian cycle. This is nothing new. What you, as the tech lead need to start realising, is that these put certain constraints on what you can and cannot do, during a 24-hour cycle.

  • If all your business decisions/prioritisation activities can mostly be done on the client side, having a remote analyst is doing a disservice to both the analyst and the remote team. The analyst, because he/she is not empowered to take decisions on the spot if needed. The team, because they are forced to subscribe to the decision cycle of the onshore clients.
  • Rotation between onshore and remote teams is a powerful tool in fostering a sense of empowerment within members of the remote members. Seeing, working and interacting with clients, closer to business realities, might just be the thing that makes everyone comfortable with the idea that the remote team “gets” it, and can function more or less autonomously.

Geography and The Broken Telephone

Geography hurts. Geography distorts. Especially if most (or all) of your project stakeholders are located in one country, and most of your development team is somewhere else. So, your development team is great. It has brilliant developers who can get stuff done. None of that means much if your remote team is unable to make decisions for itself, and operate with some degree of autonomy.

This autonomy comes with getting more information about what is happening on the ground. Frequently, this information filters down in a very sanitised, watered-down fashion. “Bob and Greg had a screaming match over the business value of so-and-so feature.” becomes “There is still ongoing discussion about whether to work on so-and-so feature.” See, this is a problem. By abstracting away details of a situation, the reality that the onshore team/client is not a single-minded amorphous blob is obscured from the remote team. The remote team is already disadvantaged in terms of the “handedness” of the information that they receive (first-hand, second-hand). Do not work to further this Broken Telephone Effect.

Of course, you don’t want to turn all your communications with the remote team into a gossip channel. However, you will want to have more informal channels of discussion with the remote teams where some minutiae of the situation can be discussed without needing to be politically correct.

Perceptions

This is not the only problem your remote team faces. Geography distorts perception in subtle ways. You’ll inevitably encounter situations where people from the onshore team — your co-located non-client colleagues — will sometimes form opinions about the remote team that are based on very limited — or even no — interactions with that team. The flavour of these opinions is very wide-ranging, but the ones you’ll want to actively combat are the ill-informed ones. This is the most insidious form of chaos that seeps in, almost unnoticed, and then informs a wide range of discussions/choices that ultimately cause frustration on both sides.

Do not let such perceptions linger if you see them.

We are not done with the problems yet. Consulting is always a challenging task, in the best of circumstances. Sometimes, it is a matter of patience. Sometimes, it means talking to a few people, planting the germ of an idea in their heads, letting them ruminate on it, and hopefully take it forward. This is very evident if you are working with very closely with your client. See, the thing is, the remote team is not seeing this. Some of them are probably thinking “What do these guys onshore really do half of the time?” This can potentially breed a skewed opinion of the onshore team. Your job, as usual, is to combat this type of thinking.

In both these cases, the ounce of prevention, as well as the pound of cure, are multiple channels of communication. You will want to keep most of these informal; whether they are scheduled or unscheduled, is up to you. But, do not let the talking die down. Silence in distributed teams can be downright poisonous.

Unit Testing AngularJS Controllers, Views, and More: Part Six, Injecting Indirect Dependencies

This is a follow-up to the series of posts on using Duck-Angular for unit testing controller, views, and bindings (Part 1, Part 2, Part 3, Part 4, and Part 5), Duck-Angular and AngularJS-RequireJS-Seed (which is what the code in this series of posts is based on) now support AngularJS 1.2.9.

What do I mean by Indirect Dependencies? It’s those dependencies that are associated with your controller/service through at least one level of indirection. Simply put, if X depends upon Y, and Y depends upon Z, X depends upon Z. Because all objects are built from the base up, they are transitive, regardless of the complexity of the hierarchy. So far, we’ve seen how to inject dependencies directly into the object(s) under test. So, what about indirect dependencies? Well, it was always possible using Duck-Angular, just slightly unwieldy to set up. No more.

Let’s start with a simple service with no dependencies:

define([], function(){
    return function() {
        this.getSomeData = function() {
            return "True Data from Svc 3";
        };
    };
});

We’ll create another service which depends upon service3. Let’s imaginatively call this service2.

define([], function(){
    return function($q, svc3) {
        var dataFromService3 = svc3.getSomeData();
        this.get = function() {
            var d = $q.defer();
            d.resolve({fromService2: "Some Data", fromService3: dataFromService3});
            return d.promise;
        };
    };
});

We intend to write a test for controller2, as a Duck-Angular test. Note that we are not mocking out service2; we want to preserve it’s original behaviour, but mock out it’s dependency service3.

it("can mock out indirect dependencies", function () {
  var service3Mock = { getSomeData: function() {
    return "Mock Service 3 Data";
  }};
  return mother.createMvc("route2Controller", "../templates/route2.html", {}, null, {service3: service3Mock}).then(function (mvc) {
    var dom = new DuckDOM(mvc.view, mvc.scope);
    expect(dom.element("#data")[0].innerText).to.eql("Some Data, Mock Service 3 Data");
  });
});

The API from spec-helper.js has the mvc() function, which looks like this:

 mother.createMvc = function createMvc(controllerName, templateUrl, dependencies, options, appDependencies) {
 ...
 };

The dependencies parameter serves for injecting direct dependencies. The appDependencies parameter is of interest here. Anything that you pass in here as a map, will be registered with AngularJS during the bootstrap process under the name corresponding to the key. This is exactly what happens when we inject service3Mock in our test.

Advice for the new Tech Lead

This post has been a long time coming. It would be nice to say that I’m speaking from a position of supreme confidence. However, I’m not; and this this post offers a menagerie of unpolished, not-fully-formed pieces of advice that I’d proffer to you if you’re just getting into the role of a Technical Lead. The title can be amorphous, and in many workplaces, doesn’t even hold much of a meaning. But, hopefully, thinking along the lines I’ve jotted down here, might give you some food for thought. I will expand on these in future posts, with links to the details.

The Realities of Distributed Development

  • Time zones and the resulting time lag between teams.
  • Chinese whispers and Information Loss
  • Perceptions

Distractions will Happen(or, Deal with It)

  • Things go Boom all the time.
  • If you have to focus, find a safe place.
  • Delegation is not an admission of defeat.

You will not Remember Everything (Or, Jot It Down)

  • Write, write, write.
  • Revise and Discard.

Voices on the Phone (are kinder than they appear)

  • Perception and Geography

Go Meta (or, Look at the Product, not the Project)

  • Think in terms of business goals and how day-to-day work as features/cards/stories achieve business goals.
  • Understand the business functionality from the end user perspective (imagine yourself in the end user’s shoes).
  • Know how the business will make money.

Push for Change(and know when not to)

Develop your own Mental Framework (or, Structure your Thought Process)

  • Build candidate frameworks
    • Different sets of factors for different domains
    • Compare things constantly to solidify your thinking.

Be the Translator (or, Expand your Circle)

  • Technical and Business

Watch for Opportunities (or, even boring Projects have hidden things for you to learn)

  • Offer to help
  • Be prepared to invest your own time in Learning/Trying out New Things.

Stay in Touch (or, you’re still a hacker at heart)

  • Do code review
  • Share
  • Spike things to try on the project

Don’t Drown (or, Stay Ahead of what is happening Right Now)

  • Day-to-day minutae
  • Think: What are the Blockers for this Release?
  • Think: What other things might expand this account?

Always have multiple options for something

  • Never rely on the first option that comes to mind.
  • Think of pros and cons of each option.

Keep track of all invariants in the system (both technical and functional)

  • Establish invariants
  • Identify when the invariants are broken and what will be the impact.

Unit Testing AngularJS Controllers, Views, and More: Part Five

I’ll speak of testing directives using Duck-Angular in this post. This is a follow-up to the series of posts on using Duck-Angular for unit testing controller, views, and bindings (Part 1, Part 2, Part 3, and Part 4), Duck-Angular and the AngularJS-RequireJS-Seed now support AngularJS 1.2.9.

Our Example Directive

Let’s use a simple directive to illustrate our unit test. directive1.js has some code which formats US phone numbers, as below:

define([], function() {
    return function () {
        return {
            link: function (scope, element, attrs) {
                    attrs.$observe("phone", function(value) {
                        var rawPhoneNumber = value.replace(/[^0-9]/g, "");
                        rawPhoneNumber = rawPhoneNumber.slice(rawPhoneNumber.length - 10, 10);

                        var areaCode = rawPhoneNumber.substr(0,3);
                        var phonePrefix = rawPhoneNumber.substr(3,3);
                        var phoneSuffix = rawPhoneNumber.substr(6,4);

                        if (rawPhoneNumber.length === 10) {
                            var prettyPrintedNumber = "(" + areaCode + ")" + " " + phonePrefix + "-" + phoneSuffix;
                            element.text(prettyPrintedNumber);
                        }
                        else {
                            element.text(rawPhoneNumber);
                        }
                });
            }
        };
    };
});

The code is pretty simple, really. It observes the value of the phone attribute on an element (which is resolved from the injected scope variable phoneNumber), and modifies the resultant text of the associated element to the formatted phone number.

The Unit Test

The test, taken from directive1-test.js, is below:

define(["spec_helper"], function(mother) {
    describe("Phone Directive", function() {
        it("can format phone number", function() {
            var template = "<span phone='{{phoneNumber}}'>{{phoneNumber}}</span>";
            var scope = {phoneNumber: "1234567890"};
            return mother.compileDirective(template, scope).spread(function(s, element) {
                expect(element.text()).to.eql("(123) 456-7890");
            });
        });
    });
});

If you’ve followed along in the previous posts, this test will be very familiar to you. The only difference is that, instead of calling mother.createController(…) or mother.createMvc(…), we call mother.compileDirective(…). This is useful for when you are just interested in testing the directive in isolation. If you’re testing a complete partial view, mother.createMvc(…) should serve just as well.

One Caveat

There is one thing to keep in mind: if you modify the scope after the initial compilation, do remember to call s.$apply() before making any assertions. Here’s an example:

define(["spec_helper"], function(mother) {
    describe("Phone Directive", function() {
        it("can format phone number", function() {
            var template = "<span phone='{{phoneNumber}}'>{{phoneNumber}}</span>";
            var scope = {phoneNumber: "1234567890"};
            return mother.compileDirective(template, scope).spread(function(s, element) {
                expect(element.text()).to.eql("(123) 456-7890");
                s.phoneNumber = "5671234400";
                s.$apply();
                expect(element.text()).to.eql("(567) 123-4400");
            });
        });
    });
});

As to what compileDirective() does, most of it is pretty similar to binding views to scopes. The function is more or less similar to createMvc() with some of the fat stripped out.

When your RequireJS-minified code misbehaves…

This is more or less directly taken from a note I dropped to my team after investigating some weird behaviour which was occurring only in the minified version of our code. Now I do need to point out that in many cases, the issue with minified code will more or less identify itself if you’re using AngularJS and have not written minification-proof code. But, but…if you’re going in blind, or are simply not sure what is wrong, hopefully this technique will help.

Preliminaries

When faced with minified code which misbehaves, you may attribute it to one (or both) of the following stages:

  • Concatenation: This is where RequireJS will trace dependencies and put everything in one single file, in the correct order. Any file may be excluded from this concatenation by using the excludeShallow option. The relevant link isĀ here.
  • Obfuscation: This is when whitespace is stripped, names are shortened, and statements are mangled while maintaining syntactic and semantic correctness. This is a global option and can be turned off by setting optimize to none. RequireJS uses the UglifyJS library by default. This implies that if you use the excludeShallow option for all files, and set optimize to none, your resulting minified source will be the same as your original, unminified, source.

Steps to debug

  • Use excludeShallow for all files, and set optimize to none, initially.
  • Minify your source and check to see if it is causing any problems.
  • If not, start removing excludeShallow from files, until you can reproduce the issue.
  • Narrow it down to the file/files which are responsible for this misbehaviour. Fix the issue, or exclude it from the minification step.
  • Turn optimize back on (set it to uglify), and verify that nothing else is broken.
  • Enjoy!

Duck-Angular updated for AngularJS 1.2.9, plus a quick recap

Update

Since publishing the series of posts on using Duck-Angular for unit testing controller, views, and bindings (Part 1, Part 2, Part 3, and Part 4), I’ve upgraded Duck-Angular and the AngularJS-RequireJS-Seed to support AngularJS 1.2.9. Below is just a quick recap of some of the things I’ve talked about already. There is more detail in the links above.

Unit Testing and Application Patterns

  • Using a module loader lets you test a controller, service, etc. in isolation without having to bootstrap AngularJS app.
  • Using a module loader allows for loading third-party dependencies without having to declare them as AngularJS objects (best of both worlds).
  • Using RequireJS makes minification a no-brainer.
  • Don’t pollute the Javascript global namespace (anything like window.*). You can isolate your entire application from external pollution.
  • Simplify testing promises using Mocha-as-Promised, Chai-as-Promised, etc. Jasmine-as-Promised also exists.
  • If you’re testing on anything below IE9, don’t have console.log() in your code.
  • Referring to router paths directly like <a href="\#/route1"/> may lead to infinite $digest loop errors.
    • Replace that with ng-click which does the actual navigation.
    • Or, add target=”_self” attribute to anchor link.
  • If you’re still using AngularJS 1.0.x and it is not too late, move to AngularJS 1.2.x now. There are quite a few things that are better, for example:
    • AngularJS 1.2.x has request interceptors (1.0.x had only response interceptors).
    • Many bug fixes for IE. Plus extra incentive to not use IE8 any more, since 1.3 and up will no longer necessarily work on IE8.
  • Don’t manipulate the DOM in Javascript.
    • Bind DOM states to $scope variables (ng-show, etc.)
    • Isolate DOM-manipulating functions that you must have in their own modules.

How to Build a Robotic Arm from Scratch: Introduction

Well, let’s clarify the phrase “from scratch” to begin with. I prefer building stuff from the ground-up, if possible. Sometimes, that leads me to the Not-Invented-Here syndrome, but within limits, I believe building things from scratch has the most self-pedagogic value. This applies to software as well, but that is a rant for another time. In the meantime, let’s come to grips with building a robotic arm. “Come to grips”, get it? Sigh. In another life, I used to work on and build robots. A lot of that stuff led to COMRADE and IRIS.

Anyway, for this exercise, we will build a 3-DOF robotic arm from the ground up. That will mean that we’ll be sawing, drilling, soldering, and, perhaps most importantly, scavenging for materials. My aim is to introduce things from their basics. We’ll try to play most of it by the ear, and not really worry about precise calculations, apart from some very rough back-of-the-envelope calculations. The old maxim of hardware still stands: “Measure twice, cut once.”

Let’s flesh out some basic parameters for this robot, starting with the degrees of freedom. These will be:

  • Rotation at the base about a vertical axis.
  • Rotation of the “upper” arm about a horizontal axis.
  • Rotation of the “forearm” about a horizontal axis.

The last operation will simply be the operation of the gripper, but we will worry about that later. The images below show some in-progress construction shots of the kind of thing we’ll be building.

20130610_190151

20130629_113154

Most of this post will be dedicated to the tools and materials you will need to get started with the mechanical construction of the arm. Some of them are optional and I note those cases.

DISCLAIMER: I will not be liable for any errors or omissions in this information nor for the availability of this information. I will not be liable for any losses, injuries, or damages from the display or use of this information.

Safety Notes

Always use the following items:

  • Protective glasses: You’ll be generating a lot of “dust” when constructing the arm. Definitely get a pair of these.
  • Gloves: Tools do not care whether they are drilling/cutting/sawing metal or flesh. A deformed workpiece can be replaced: a missing finger cannot. Take care.
  • Mask: Not always needed, but useful when sawing. It can be as simple as a wet piece of cloth wrapped around your nose and mouth.

In addition, make sure that your electrical outlets have proper earthing. This will only become more important when we get to testing our electronic circuits.

Tools (Mechanical)

  • Hammer: The most common use of the hammer will be in conjunction with a drill punch to mark the center of holes you’ll drill in aluminium/plastic workpieces. Besides this, very handy for bending plate strips for mounting brackets.
  • Punch: You’ll need this precisely mark the position of a hole you want to drill. The depression caused also prevents the drill bit from “walking” when you initially begin drilling.
  • Drill/Driver: For drilling holes, obviously. I also use it to tighten screws by substituting a screwdriver bit for the usual drill bit. Keep a manual drill as backup for those occasions when there is a blackout before you can drill through that last millimetre.
  • Drill bits: You’ll never need very thick drill bits, and HSS (High Speed Steel) bits will serve for drilling through plastic/aluminium. But you’ll need one or two carbide/cobalt bits for drilling through shafts.
  • Hole saws: You’ll need these to build housings for ball bearings.
  • Vice: You’ll need one bench vice, and probably one C-clamp. The bench vice is a necessity.
  • Screwdrivers: The basic slotted and Philips-type screwdrivers will do fine. Depending upon what screws you’re using, a precision screwdriver may be a better option.
  • Hacksaw: You’ll need this for sawing through plastic/aluminium. Also, make sure to get blades designed for sawing metal. Investing in a hacksaw with a more comfortable rubber grip will definitely make it easier.
  • Pliers: For tightening nuts, and bending thinner pieces of work.
  • Lubricant for drill bits: Helps extend the life of your drill bits. WD-40 works fine for this purpose.
  • Ruler and markers: For general measurement and marking.

Optional Tools (Mechanical)

  • Jigsaw: Handy for when you need to cut irregular shapes. Because it is electrically powered, all you need to do is guide it. Note though, that you need to clamp down your workpiece securely if you want to use this, with two C-clamps, for example.
  • Reciprocating Saw: For when your arms are to lazy to use a hacksaw. Also electrically powered, you should not really need it.

Materials

  • Aluminium sheets: You’ll need these mostly to build struts to build rigidity into your arm.
  • HDPE sheets/rods/bars: A form of high-density plastic commonly used in making cutting boards in kitchens.
  • Screws and nuts: For fastening things to other things.
  • Gears and Chains: The primary form of power transmission across joints.
  • Printer shafts: For mounting gears and other rotational elements.
  • DC motors with gearboxes: The actuators.
  • Ball bearings: For reducing friction.

The last few items in the list above are things which fall into the “scavenged” category. In Bangalore, there is a flea market on Sunday which sells all sorts of broken machinery, including printers, bike chains, and scavenged motors. You have a high chance of finding materials there. Similarly, aluminium sheets/HDPE bars are more or less easily available on S.P. Road in Bangalore.

There will be more things we’ll need later to build in feedback control, like potentiometers, or maybe even Hall Effect sensors, but this is all you need to get started. Any other things we’ll need in the later stages of construction, I’ll point those out when we come to them.

A Note on the Work Area

Make sure it is well-lit, and well-ventilated. When sawing, you’ll generate a lot of dust. Wear a mask, protective glasses, and your work gloves. It does not have to be anywhere special. I converted my kitchen into my workshop when I was building this.

Some Photos

My Workshop

Basically, my kitchen. At some point, I do intend to construct a proper workshop table, but for now, this should suffice. And no, I don’t cook in there.

20130608_155240

Scavenged Materials

Pictured here are gears, ball bearings, and printer shafts)

20130706_150908

Materials

Pictured here are HDPE rods and aluminium sheets.

20140122_232607

In the next post, we’ll play around a bit with building some components that we can repeatedly use in our design, like the ball bearing housings.

Unit Testing AngularJS Controllers, Views, and More: Part Four

Link to Part One of this series

Link to Part Two of this series

Link to Part Three of this series

The AngularJS-RequireJS-Seed used for reference is here.

Duck-Angular is here.

This post contains a grab bag of miscellaneous topics to afford a deeper understanding of Duck-Angular, as well as some nuances/pitfalls of unit testing in AngularJS.

Mocking HTTP the way you want

Yeah, you can mock $httpBackend. However, most of the time, you can get away by just mocking $http itself. Here is an example from service1-test.js, which shows you how to do this. The primary reason to use the success() and error() API’s of $http is that these methods provide wrappers over the usual single-argument then() clause, to expand the parameters into the familiar (data, status, headers, config) format. We don’t need to unpack this information ourselves. Thus, to mock out $http directly, the thing to mock out are these functions.

Also note, these failure handlers can be chained, so that every mocked function (success() and error()) must return a promise.

define(["service1", "Q"], function (Service1Ctor, Q) {
  describe("Service1", function () {
    it("should work, even if the HTTP call succeeds", function (){
      var httpResponse = {successful: false};
      var promise = Q.reject(httpResponse);
      promise.success = function(onSuccess) {
        promise.then(function(data) { return onSuccess(data); });
        return promise;
      };
      promise.error = function(onError) {
        promise.fail(function(err) { return onError(err); });
        return promise;
      };
      var getStub = sinon.stub().returns(promise);
      var httpMock = {get: getStub};
      var service1 = new Service1Ctor(Q, httpMock);
      var run = service1.getHttp("http://google.com");
      return expect(run).to.be.rejected;
    });
  });
});

A bit verbose, but this can be abstracted into a mock builder function. I find it easier to use this approach when I’m mocking out an $http dependency, instead of having to register Angular modules, and go through the whole bootstrap process.

Why $q won’t always work

Here is a simple unit test from controller1-view-test.js. There’s nothing special about this unit test: all it does is returns a pre-resolved promise.

it("can prove that $q won't work in a plain unit test", function () {
  return mother.createMvc("route2Controller", "../templates/route2.html", {}).then(function (mvc) {
    var injector = mvc.injector;
    var $q = injector.get("$q");
    var d = $q.defer();
    d.resolve({});
    return d.promise;
  });
});

When you run this test, you will be greeted with a Mocha timeout error, like so:

Error: timeout of 10000ms exceeded
    at http://localhost/example/static/js/test/lib/mocha/mocha.js?bust=1388996292503:3993:14

The reason using $q in place of Q in a simple unit test will not work is that *$q‘s mechanics are intimately tied to AngularJS’ scope lifecycle. Indeed, if you take a look at the code for $q (inside QProvider), you’ll see a call to $evalAsync(), which makes no guarantees about when the callback will be invoked, except for the following:

  • It will execute in the current script execution context (before any DOM rendering).
  • At least one $digest cycle will be performed expression execution.

The simple fix for all these situations is to use Q instead of $q. Should you have to fulfil the $q dependency for a service or a controller in a simple unit test (one that does not bootstrap AngularJS modules), inject Q.

Resolving child templates

A template may have multiple partials, each of which might contain further nested partials. Normally, when you’re unit testing templates, this loading/binding of the nested partials is handled for you entirely by AngularJS. But there is a caveat: we do not really know when all the partials have loaded.

In older versions of Duck-Angular, trying to unit test templates which had nested partials, could sometimes result in errors, because the test had started before AngularJS had resolved and bound all the nested partials. In most cases, the expansion of these partials would not happen, and any assertions on DOM elements expected to be inside these partials would fail.

Currently, Duck-Angular fixes this by making use of the copious event publishing mechanisms that AngularJS provides. The event that we will focus on for this discussion is the $includeContentLoaded event. This event is published whenever a partial is loaded using the ng-include directive. How does this help us? Well, if we know how many partials exist in a template (regardless of the level of nesting), we can set up a counter that ticks every time the $includeContentLoaded event is fired, and only begin our test when the counter reaches the number of partials that we detected.

That sounds very well in theory, except for one tiny wrinkle: we need to actually load up all the partials to actually find out how many partials there are, to begin with. That is exactly what Duck-Angular does. It creates a chain of promises. Each promise is responsible for loading a separate partial. Once this partial is loaded, this promise is chained with other promises which, in turn, load up child partials. The result of each promise fulfilment is one plus the fulfilment value of the child promises.

This is simply a recursive chain of promises, each of which aggregate the counters of its child promises, and passes it up the tree. The result is the total number of promises spawned, which has a one-to-one correspondence with the number of partials loaded. The code below from duck-angular.js illustrates this.

  var includes = element.find("[ng-include]");
  if (includes.length === 0) {
    return Q.fcall(function () {
      return 1;
    });
  }

  var promises = _.map(includes, function (include) {
    var includeSource = angular.element(include).attr("src").replace("'", "").replace("'", "");
    var includePromise = requireQ(["text!" + includeSource]);
    return includePromise.spread(function (sourceText) {
      var child = self.removeElementsBelongingToDifferentScope(self.createElement(sourceText));
      return num(child);
    });
  });
  return Q.all(promises).then(function (counts) {
    return 1 + _.reduce(counts, function (sum, count) {
      return sum + count;
    }, 0);
  });
};

Unit Testing Pitfalls

  • If you’re using Mocha-as-Promised, make sure to always explicitly return a promise. If you do not do this, the test will most likely appear to pass (because Mocha has no way of deciding when the test has finished), but would have probably failed.

  • A good practice while using Chai-as-Promised is to use the should.be.fulfilled() and the should.be.rejected() clauses, instead of using the simple then() clause. If your promise fails, any assertions/steps in the then() clause will never be executed, and your test will appear to have succeeded. Using Chai-as-Promised’s explicit fulfillment/failure verification prevents this from happening.

This (kind of) concludes this series on unit testing AngularJS controllers and views, using Duck-Angular. I’ll probably update the code to use AngularJS 1.2.x, since that is the latest production release branch. If there are any corrections/errata arising from that, I’ll update in a separate post.

Unit Testing AngularJS Controllers, Views, and More: Part Three

Link to Part One of this series

Link to Part Two of this series

The AngularJS-RequireJS-Seed project for this guide is here.
Duck-Angular is here.

The Story so Far

We will continue from where we left off, which is having written unit tests for two of our controllers. We’ve seen two techniques so far.

  • The plain constructor approach, by virtue of starting off a controller/service/factory, etc. as a RequireJS module. Here, we’ve had to necessarily supply all the dependencies to the controller.
  • The bootstrapped app approach, where we bootstrapped the full app, used the $controller service to access the controller, and pass in a subset of the dependencies to the controller. Dependencies that we did not inject, were fulfilled with their production values.

Unit Testing a View

However, so far, views have not featured in any of our tests. It is time to do that. This will also illustrate some of the convenience of using Duck-Angular. Before illustrating this aspect, we’ll make some small additions to controller2.js and its corresponding view.

We add two new scope methods to controller2.js.

$scope.changeSomeText = function() {
  $scope.data = "Some New Data";
};

$scope.refreshData = function() {
  return service2.get().then(function(data) {
    $scope.data = data;
  });
};

Pretty self-explanatory, changeSomeText() modifies $scope.data. refreshData() does too, but it refetches the data from service2 before doing this. We also modify the view, in this case, route2.html, like so:

<div>
  This is route #2
  <a href="" ng-click="go()">Click here to go to Route 1</a>
  Data: <span id="data">{{data}}</span>
  <div>
    <a id="changeLink" href="" ng-click="changeSomeText()">Click here to change data</a>
  </div>
  <div>
    <a id="refreshLink" href="" ng-click="refreshData()">Click here to refresh data</a>
  </div>
</div>

This simply adds two links which call the functions that we just grafted onto our scope. If you run the app, you will see two links, one to modify the data (to “Some New Data“), the other to refresh the data (to “Some Data“).

Our first test (controller1-view-test.js) will look like this:

it("can show data", function () {
  return mother.createMvc("route2Controller", "../templates/route2.html", {}).then(function (mvc) {
    var dom = new DuckDOM(mvc.view, mvc.scope);
    expect(dom.element("#data")[0].innerText).to.eql("Some Data");
  });
});

There is a bunch of things we do here, so pay attention.

  • The createMvc() function is responsible for setting up the controller and scope, and binding the view to this scope. Along the way, any dependencies that we need to inject explicitly, can be done through the third parameter. In this case, we don’t really have to, so we just pass in an empty hash.
  • createMvc() returns a promise, which, upon resolution, returns us an object that we refer to as mvc. The mvc object contains a bunch of things. Some of them are the scope, the controller, and the compiled template. The compiled template reflects what the view would look like the first time it is initialised, after the controller has had the chance to set it up. The mvc object also contains the injector, in case we need to retrieve some other registered objects.
  • Once this has been set up, we initialise a DuckDOM object. This is really a thin wrapper over JQuery/jqLite with some smarts built-in with regard to user interaction. The DuckDOM object needs the view and the scope to be of any use, which we grab from the mvc object.
  • The expectation simply checks that the inner text of the “data” element is equal to “Some Data“.

This allows us to test scope/view bindings very cheaply. No Selenium, no external browser, just a unit test.

Asserting on User Interactions

But that is not all. On without pause to the good bit, let’s test user interactions.

it("can update data", function () {
  return mother.createMvc("route2Controller", "../templates/route2.html", {}).then(function (mvc) {
    var dom = new DuckDOM(mvc.view, mvc.scope);
    var interaction = new UIInteraction(dom);
    expect(dom.element("#data")[0].innerText).to.eql("Some Data");
    dom.interactWith("#changeLink");
    expect(dom.element("#data")[0].innerText).to.eql("Some New Data");
  });
});

This test builds upon the first one. Critically, it adds an interactWith() call, which triggers a click on the link with ID “changeLink”. The succeeding expectation asserts that the data in the view has indeed changed. Again, note: this is just a unit test. This lets us test user interactions quite quickly.

Handling Asynchronous User Interactions

In most scenarios, the result of a user interaction may be an asynchronous action, like a service call. The refreshData() method defined in controller2.js is one such example. If we want to test this interaction, we’ll need to make a slight change. We’ll have to tell Duck-Angular which method it should wait for, before proceeding to making assertions. Without this information, the test run could potentially be unpredictable.

The method which actually performs the service2.get() call is refreshData(). Thus, it is logical to wait until it finishes. Or, in terms of promises, we wait until the refreshData() promise is fulfilled.

it("can reflect data that is refreshed asynchronously", function () {
  return mother.createMvc("route2Controller", "../templates/route2.html", {}).then(function (mvc) {
    var dom = new DuckDOM(mvc.view, mvc.scope);
    var interaction = new UIInteraction(dom);
    expect(dom.element("#data")[0].innerText).to.eql("Some Data");
    dom.interactWith("#changeLink");
    expect(dom.element("#data")[0].innerText).to.eql("Some New Data");
    return interaction.with("#refreshLink").waitFor(mvc.scope, "refreshData").then(function() {
      expect(dom.element("#data")[0].innerText).to.eql("Some Data");
    });
  });
});

Currently, Duck-Angular supports interactions with all common UI elements like buttons, links, checkboxes, radio buttons, dropdowns, and text boxes. Extra behaviour can be easily added by modifying the interactWith() method in duck-angular.js.

What Next?

Let’s review what we set out to do:

  • We wanted to unit test controller logic independent of AngularJS.
  • We wanted to unit test scope bindings in templates.
  • We wanted to unit test user interactions, and their consequences on views.

Now that the most basic demonstration is out of the way, I intend the next post to cover the following topics:

  • Good practices while unit testing with promises
  • The pitfalls of $q
  • How Duck-Angular resolves partials (templates included within templates)
  • How Duck-Angular achieves waitFor()

Unit Testing AngularJS Controllers, Views, and More: Part Two

Link to Part One of this Series on Angular Unit Testing using Duck-Angular

When we last left off, I’d discussed the structure of the application, and why I was using RequireJS (and Q). In this post, I’ll speak of the way the tests are set up. For the most part, it will parallel the application folder structure, but there are a few things that will be worth noting. For reference, I’m still using the AngularJS-RequireJS-Seed project to talk you through the details. The Duck-Angular project is here.

The files pertinent to the initial part of this post are:

  • test-main.html
  • test-main.js
  • test-setup.js
  • test.config.js

It might be easiest to explain these files by drawing parallels between them and the production bootstrap code.

Unit Test Setup

  • test-main.html is analogous to index.html. This is the file that kicks everything off. This may be run inside an actual browser like Chrome, or it may be run from the command line using libraries like Mocha-PhantomJS. Perusing this file indicates that it loads up test-main.js.
  • test-main.js does not have any analog in the production code because it does a bunch of test-specific things. Among them:
    • It lists the unit test files which will be run.
    • It sets up the parameters for Mocha, like timeout and the assertion style. It also enables the Mocha-as-Promised extension.
    • It sets up Chai’s assertion style (“bdd” in this case), and also enables Chai-as-Promised.
    • Finally, it runs the unit tests.
    • As part of test-main.js, the file test-setup.js is also loaded. test-setup.js is simply the combined unit test analog of bootstrap.js and app.js, but crucially, even though it has all these functions to setup/bootstrap the app, it does not actually execute them. Think of these functions as helper functions, which can be used by the unit test to set up the AngularJS environment. The important thing to note here is, if you’re using Duck-Angular, you’ll never need to all these methods directly. In this example, I’m using spec-helper.js a lot, and that’s the module which actually uses these bootstrapping functions defined in test-setup.js.
  • Finally, test.config.js maps the test-specific modules to the correct file paths.

The First Controller unit test

We are (mostly) set to write our first unit test against a controller. This one will probably be a little anticlimactic, because at the end of all this setup, all you will really do is load a RequireJS module, and use the resulting object in your test. But this does illustrate how easily you can test AngularJS objects if you don’t start them off…as AngularJS objects. But fret not, we’ll be writing more involved tests (views and controllers and services and whatnot) very soon :-)

Let’s look at the controller that we want to unit test. This is from controller2.js

define([], function() {
  return function ($scope, $location, $q, service2) {
    var deferredLoaded = $q.defer();
    this.loaded = deferredLoaded.promise;
    $scope.go = function() {
        console.log("Was called");
        $location.path("/route1");
    };

    console.log("In controller2");
    service2.get().then(function(data) {
        $scope.data = data;
        console.log("Service2 returned");
        deferredLoaded.resolve();
    });
  };
});

The controller defines a method go() on its scope, which navigates to /route1. The other thing it does, on initialisation, is call service2.get(), presumably to get some data, which it then sets back on to the scope. This is an asynchronous operation. Having done this, it fulfills a promise which is available to anyone who might want to act on it. The variable ‘deferredLoaded’ is used for this purpose.

The Loaded Promise Convention for Controllers

In most cases, it makes sense to have the controller fulfill a promise to signal that it is done “loading”. Loading implies completing any and all asynchronous operations. This is very useful for predictable unit tests, because if there’s a promise that has not been fulfilled in time, and an assertion depends upon that promise having been fulfilled, you have unpredictable tests which sometimes pass, and sometimes fail. Duck-Angular expects your controller to have a loaded promise. Even if your controller does not perform any asynchronous operation, having a pre-resolved promise is simple boilerplate that can be abstracted away.

The first test that we’ll write simply asserts that the scope is set up as intended. We’ll mock out service2 so that we are only testing controller behaviour. Here is a snippet from controller2-test.js.

it("can set data on scope", function () {
  var service2 = { get: sinon.stub() };
  service2.get.returns(Q("Some Mock Data"));
  var location = { path: sinon.stub()};
  var scope = {};
  var controller = new Controller2Ctor(scope, location, Q, service2);
  return controller.loaded.then(function() {
    expect(scope.data).to.eql("Some Mock Data");
  });
});

So, let’s dissect the dependencies.

  • service2 has been stubbed to return “Some Mock Data“. Note that it returns a promise, instead of the value directly. This maintains the illusion that the client of service2 is still dealing with asynchronous code.
  • scope is just an empty object, no surprises here.
  • location is an object with a single stub method get(). Strictly speaking, this is not needed here; an empty object would have sufficed.
  • The $q dependency has been satisfied with Q. There is a reason why AngularJS’ $q library will not work (in many cases) inside unit tests. I’ll write a simple test to demonstrate this later, and explain why.

Anyway, the rest of the code is more or less easy to follow. We make an assertion about the state of scope after the controller.loaded promise is fulfilled, because, of course, that’s when we can be sure that the state of the scope has been altered. The other interesting thing to note is that we are actually returning a promise from the test. If we were using the raw Mocha library, we’d have to invoke done() to signal to Mocha that the test has completed. However, because we are using Mocha-as-Promised, we return a promise at the end of a test. Whether the promise is fulfilled or rejected, determines the success (or failure) of the unit test.

Sinon to the Fore

On without pause to the next controller test. This one will be similar in structure to the previous test, but will assert that triggering the go() method in the controller causes a navigation to /route1. Of course, in this restricted AngularJS-free sandbox, we won’t really perform this navigation; we will simply verify that $location.path() method is called with the appropriate parameter (“/route1” in this case).

Let’s look at the test. This is from controller2-test.js.

it("can navigate to another route", function () {
  var service2 = { get: sinon.stub() };
  service2.get.returns(Q("Some Mock Data"));
  var location = { path: sinon.stub()};
  var scope = {};
  var controller = new Controller2Ctor(scope, location, Q, service2);
  return controller.loaded.then(function() {
    scope.go();
    expect(location.path.calledWith("/route1")).to.be.ok;
  });
});

Mostly the same, except the part inside the fulfillment handler. The scope.go() method is fired, and we expect location.path() to be called with “/route1“. This kind of test is very useful when firming up logic inside controllers.

Inject what you Want, let AngularJS do the Rest

Many times, you may want to mock out only some of the dependencies, but need the rest to be fulfilled by the production dependencies. To demonstrate this, let’s look at controller1.js.

    define([], function() {
      return function ($scope, service1, $q) {
        var deferredLoaded = $q.defer();
        this.loaded = deferredLoaded.promise;

        console.log("In controller1");
        service1.get().then(function(data) {
            $scope.x = data;
            deferredLoaded.resolve();
        });
      };
    });

This is very similar to controller2.js, and simpler. All it does is get some data from service1, and set it on the $scope as x. Let’s assume that we want to unit test this controller, but we do not want to mock out service1‘s dependency. How do we go about doing this? Here’s the short answer, from controller1-test.js.

    define(["spec_helper", "Q"], function (mother, Q) {
      describe("Controller1 Test", function () {
        it("sets up real registered service if dependency is not explicitly provided", function () {
          var testScopeMock = {};
          return mother.createController("route1Controller", { $scope: testScopeMock, $q: Q}).then(function(controller) {
            expect(testScopeMock.x).to.eql("Real Service1 Data");
          });
        });
      });
    });

If you look at service1.js, it returns a promise with the value “Real Service1 Data“, and that is the expected value we are testing against. In the test above, we inject $scope and $q, but we do not inject the service1 dependency. Yet, that dependency is fulfilled. What sort of magic is happening inside mother.createController()?

A Gander inside Duck-Angular

As it turns out, not a lot. We’ll have more than one occasion to examine the guts of Duck-Angular, and this is one of them. Before I dive into the code inside mother.createController(), it will be instructive to review how you can retrieve a controller which has been registered with AngularJS.

The easiest way is through the $controller service. The $controller service itself may be accessed through the application’s injector. After that it is mostly a matter of asking for the controller by its registered name. However, to get the injector, we need to have bootstrapped the application. This is precisely what happens inside the createController() function. Here’s the relevant code from spec-helper.js.

mother.createController = function createController(controllerName, dependencies) {
  return initApp().spread(function (injector, app) {
    mother.injector = injector;
    var container = new Container(injector, app);
    var resourceBundleFactory = container.injector.get("ngI18nResourceBundle");

    return resourceBundleFactory.get("en").then(function (resourceBundle) {
      var controller = container.controller(controllerName, dependencies);
      dependencies.$scope.resourceBundle = resourceBundle.data;
      mother.resourceBundle = resourceBundle.data;
      return controller;
    });
  });
};

You can safely ignore all the resourceBundle calls. For now, suffice it to say that the initApp() function is called (remember, initApp() was defined in test-setup.js). After this, the Container is set up with the injector and the app. When the time comes to get the controller, we simply ask the Container to give it to us. This is the relevant code from duck-angular.js.

self.controllerProvider = self.injector.get("$controller");
....
this.controller = function (controllerName, dependencies) {
  var deferred = Q.defer();
  var controller = self.controllerProvider(controllerName, dependencies);
  controller.loaded.then(function () {
    deferred.resolve(controller);
  });
  return deferred.promise;
};

It basically translates to a simple call the the $controller service. The $controller service is responsible for accommodating our injected dependencies, as well as autowiring those which have not been explicitly injected.

In the next part of this series, I’ll talk of the nuances of using Q instead of $q, a nice way to mock $http‘s success()/failure() clauses, and start wiring up views to controllers in our unit tests, while digging more inside Duck-Angular’s internals.

Programming / Drawing / Robots / Machine Learning