Which approach is best to unit test composed code? - angularjs

Say I have the following AngularJs service:
angular.module("foo")
.service("fooService", function(){
var svc = this;
svc.get = function(id){...};
svc.build = function(id){...};
svc.save = function(thing){...}; //posts, then returns the saved thing
svc.getOrCreate = function(id){
return svc.get(id).then(function(thing){
return thing || svc.build(id).then(function(builtThing){
return svc.save(builtThing);
});
});
}
});
I can unit test the get method by making sure the right API endpoint is being reached, with the right data.
I can test the build method by making sure it pulls data from the proper endpoints/services and builds what it's supposed to.
I can test the save method by making sure the right API endpoint is being reached.
What should I do to test the getOrCreate method? I get two differing opinions on this:
stub the get, build and save methods and verify they're called when appropriate, and with the proper parameters
stub the API endpoints that are being called in get and build, then verify that the endpoints within save are being called with the proper parameters
The first approach is basically saying, "I know these three methods work because they're independently tested. I don't care how they actually work, but I care that they're being called within this method."
The second approach is saying, "I don't care about how this method acts internally, just that the proper API endpoints are being reached"
Which of these approaches is more "correct"? I feel the first approach is less fragile since it's independent of how the get, build and save methods are implemented, but it's not quite right in that it's testing the implementation instead of the behavior. However, option 2 is requiring me to verify the behavior of these other methods in multiple test areas, which seems more fragile, and fragile tests make people hate programming.
This is a common tradeoff I find myself facing quite often with tests... anybody have suggestions on how to handle it?

This is going to come down to a matter of opinion.
If you are unit testing your tests should work on very specific functionality.
If you start chasing promises, and you have promise chaining, where does it stop?
Most importantly, as your unit test scope gets bigger and bigger, there are more things that it depends on (services, APIs etc...), and more ways in which it can brake that may have nothing to do with the "unit". The very thing that you want to make sure works.
Question: If you have a solid controller that works great with your template, and a unit test that ensures your controller is rock solid. Should a twice detached promise that resolves from the response of a web service http API call break your controller test?
On the other hand, the same way you test your API client end points by mocking the service, you can test the service with its own tests using something like Angular's $httpBackend service.

I have seen it done both ways and don't have a strong preference either way. Personally, however, I would consider option 1 where you don't mock the other functions that are tested elsewhere to be integration tests because they're calling multiple publicly visible functions and therefore would prefer option 2.

Related

Is testing correct $scope initialization an example of "testing someone else's code"?

I'm new to testing, and I understand it's not a good practice to write unit tests that test third-party packages. But I'm curious if the following test would constitute testing the AngularJS framework itself:
describe("TestController", function () {
it("should set up the $scope correctly", function () {
expect($scope.foo).toBe("bar");
});
});
Is it a good idea to test that your $scope got initialized correctly, or since that's AngularJS's job and not yours, is that something you should avoid writing a test for? Sorry if this has an obvious answer, but I want to make sure I'm teaching correct principles when I teach this to my students.
In your example, you are testing the behaviour of TestController, which is a class that you wrote, i.e. you are testing your own code.
You are not testing if Angular can set the state properly if you tell it to (which would indeed be a bit redundant, as it is already covered by Angular tests), you are asserting that your code does the things your application requires it to do (that this involves calling Angular functions is secondary).
So that's a good test to write.
Depending on your application, it may be possible to check the same behaviour in a more "high-level" fashion than asserting what exact value a given state variable has. For some applications that could be considered an implementation detail and not the most appropriate way to validate correct behaviour. You should not be testing internal state, but externally visible behavior. In this case, though, since you are testing a controller, and all a controller does is update the state, it's probably appropriate.
If you find that all you are doing in the controller is unconditionally set state, without any logic involved, then you may not really have a need to test the code at that level of granularity (maybe test bigger units that in combination do something "interesting"). The typical example here is testing setter/getter methods: Yes, there is a chance that you get these one-liners wrong, but they make really boring tests, so you might want to skip those (unless they can be automatically generated).
Now, if this test fails, it could be for three (not mutually exclusive) reasons:
1) your code is broken (either some state setup is missing or you are not doing it right). Detecting this is the main purpose of unit testing.
2) Angular is broken (you set the state properly, but somehow Angular lost it). That is unlikely, but if it does happen, you now have a test case to attach to your bug report to Angular. Note that you did not set out to write a test case for Angular, but you got one "by accident".
3) your code as well as Angular are correct, but your test code is wrong. This happens frequently when you update the code that is being tested and test code also needs to be adjusted because its assumptions have been too narrow, or the expected behaviour has changed and the test is now simply outdated.

How do I unit test basic ngResource based services?

I have a decently large number of basic services, most of which are defined exactly the same:
app.factory('Group',['$resource',function (resource) {
return resource('/api/group/:group', {group:'#id'},{});
}]);
And so on. A very few are slightly different, and either have unique properties, e.g. a User might also have activation:
app.factory('User',['$resource',function (resource) {
return resource('/api/user/:user', {user:'#id'},{
activate: {method:'PUT', url:'/api/activate/:user'}
});
}]);
Or force some expected response, e.g. GET might give an array:
app.factory('GroupMembers',['$resource',function (resource) {
return resource('/api/group/:group/members', {group:'#id'},{
get: {method:"get",isArray:true}
});
}]);
I am looking for a sane way to unit test these. It seems like using $httpBackend to capture all of the requests is a bit overkill, but stubbing in $resource might be underdone. Would I be better served with either of those approaches? Or perhaps some function suite of tests that exercises all of the get/put/post/patch/delete/query and overrides for specific cases like the added activate for User or special get for GroupMembers?
IMO you should not be testing your resources as this would be testing the framework itself. You should rather test your other services and controllers that use the resources. For such tests both approaches (mocking the resources or the $httpBackend) will do the job, so you just have to pick the more straight-forward one for you. I would vote for Sunil D.'s suggestion to mock the resource as it isolates it from the test target.
If you feel you need to verify if you declared the service property you may write very simple tests just for the resources mocking the $httpBackend, but I would not waste my time in such tests as the critical part of the code is in the framework.

Angular unit testing nested functions

I my angular project I have a service1 that depends on service 2. Service1 is sending a rather complex function for callbackSuccess into service2
service2.js
this.getData = function (url, callbackSuccess, callbackError) {
I'm not sure whether there is much point unit testing service2 and I should rather focus on service1 since most of the logic is contained in there. Can someone advise?
You could simply create a spy on the function in service2 or mock out service2 completely.
var data_spy = spyOn(service2, 'getData').andCallFake(
function(url, callbackSuccess, callbackError) {
callbackSuccess(mock_data); // Mock the data somewhere
}
);
Using this is a good idea since it removes the dependence on service2 functionality in your test. Although you should still consider testing service2.
Some other advice. This model seems to lend itself very well to promises, since there is a resolve and reject callback. I recommend you take a look at $q documentation.
Hope this helped!
Should you test service2?
If service2 is obviously correct because it is so simple you can inspect it - then you probably do not need tests for it. However if it is any more complex then that, then you probably want to test it.
I can see that it must be doing at least 3 things:
does something with url
calls success callback only if operation was successful, and calls it with all the correct parameters based upon output of operation
calls error callback only if operation was not successful, and calls it with all the correct parameters based upon the output (such as error codes and messages)
To me, this amount of work would lead me to add some tests - haven't even though about exception handling for instance... The testing of it, since it is simple, should also be simple.
Testing service1
If service1 contains a complicated callback then it definitely should be tested. Make sure that callback is accessible from your tests so you can test it thoroughly in isolation from the rest of what service1 might be doing before passing it off to service2.
Conclusion
Ultimately you are asking an opinion question, and one that relies upon a lot of information about your codebase, goals, and deadlines which we do not know. My best answer is: test service2.

Can a Mock framework do this for me?

I am a bit confused
from wiki:
"This means that a true mock... performing tests on the data passed into the method calls as arguments."
I never used unit testing or mock framework. I thought unit tests are for automated tests so what are mock tests for?
What I want is a object replacing my database I might use later but still dont know what database or orm tool I use.
When I do my programm with mocks could I easily replace them with POCO`s later to make entity framework for example working pretty fast?
edit: I do not want to use unit testing but using Mocks as a full replacement for entities + database would be nice.
Yes, I think you are a bit confused.
Mock frameworks are for creating "Mock" objects which basically fake part of the functionality of your real objects so you can pass them to methods during tests, without having to go to the trouble of creating the real object for testing.
Lets run through a quick example
Say you have a 'Save()' method that takes a 'Doc' object, and returns a 'boolean' success flag
public bool Save(Doc docToSave(){...}
Now if you want to write a unit test for this method, you are going to have to first create a document object, and populate it with appropriate data before you can test the 'Save()' method. This requires more work than you really want to do.
Instead, it is possible to use a Mocking framework to create a mock 'Doc' object for you.
Syntax various between frameworks, but in pseudo-code you would write something like this:
CreateMock of type Doc
SetReturnValue for method Doc.data = "some test data"
The mocking framework will create a dummy mock object of type Doc that correctly returns "some test data" when it's '.data' property is called.
You can then use this dummy object to test your save method:
public void MyTest()
{
...
bool isSuccess = someClass.Save(dummyDoc);
...
}
The mocking framework ensures that when your 'Save()' method accesses the properties on the dummyDoc object, the correct data is returned, and the save can happen naturally.
This is a slightly contrived example, and in such a simple case it would probably be just as easy to create a real Doc object, but often in a complex bit software it might be much harder to create the object because it has dependencies on other things, or it has requirements for other things to be created first. Mocking removes some of that extra overload and allows you to test just the specific method that you are trying to test and not worry about the intricacies of the Doc class as well.
Mock tests are simply unit tests using mocked objects as opposed to real ones. Mocked objects are not really used as part of actual production code.
If you want something that will take the place of your database classes so you can change your mind later, you need to write interfaces or abstract classes to provide the methods you require to match your save/load semantics, then you can fill out several full implementations depending on what storage types you choose.
I think what you're looking for is the Repository Pattern. That link is for NHibernate, but the general pattern should work for Entity Framework as well. Searching for that, I found Implementing Repository Pattern With Entity Framework.
This abstracts the details of the actual O/RM behind an interface (or set of interfaces).
(I'm no expert on repositories, so please post better explanations/links if anyone has them.)
You could then use a mocking (isolation) framework or hand-code fakes/stubs during initial development prior to deciding on an O/RM.
Unit testing is where you'll realize the full benefits. You can then test classes that depend on repository interfaces by supplying mock or stub repositories. You won't need to set up an actual database for these tests, and they will execute very quickly. Tests pay for themselves over and over, and the quality of your code will increase.

Avoid Database Dependency For Unit Testing Without Mocking

I've got many objects with methods that require database access. We're looking to get into unit testing but are keen to avoid the use of mock objects if possible. I'm wondering if there is a way to refactor the Validate method shown below so that it wouldn't need db access. In the actual application there is usually a fair bit more going on but I think this simplified example should be enough.
We'll learn to use mock objects if we need to but it just seems like a lot of overhead, so I'm looking for alternatives.
public class Person
{
public string Name;
public string Validate()
{
if (PersonDA.NameExists(Name))
{
return "Name Already Used";
}
}
}
Personally I'd just go the mock object route. It's much more flexible and it sounds like you're wanting to go the route of putting test code in your actual object?
Regarless, extract the validation code into a PersonValidator object with a method for boolean isValid(Person). Then in the test code use a mock validator which just returns true or false based on the test case.
The Person class is hard to unit-test because it has a hidden, static dependency on database access code. You can break this coupling by introducing a dynamic collaboration between the Person and some new type of object that provides it with the information it needs to validate its state. In your unit tests of the Person you can test what happens when it is valid or invalid without hitting the database by passing the Person object "stub" implementations of it's collaborator.
You can test the real implementation, which hits the database, in a separate set of tests. Those tests will be slower but there should be fewer of them because they will be direct translations of accessor methods to database queries with no complex logic of their own.
You can call that "using mock objects" if you like but, because your current design means you only need to stub queries, not expect commands, a mock object framework is a too complicated tool for the job. Hand-written stubs will make test failures easier to diagnose.
Take a look at dbunit, it's especially set up to populate a small test database so you can use your real objects on a mock database during unit testing. Testing with it is far easier than developing mock objects, far safer than modifying your data access code, and far more thorough than either.
Why are you trying to avoid mocks exactly? If you are going to practice unit testing and you have data access code, its going to be easiest to get comfortable with the mock/stub/inject way of doing things.
If it's because you dont want to bring in a mocking framework you could code up some simple stubs as you need them.
Putting your data access code behind an interface will let to avoid the need for a database. Consider using dependency injection to insert the mock or stub data access code during your tests.
You should just set up a database that is used for the unit testing.
If you use mockups for all the data access, you wouldn't actually be testing much? :)

Resources