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.
Related
So I'm trying to get into TDD with React. Everywhere I read about testing in general, it's always emphasised that we only want to test behaviour, not implementation details. Sounds good, but then when going through some examples, I find stuff like this:
expect(onSubmit).toBeCalledTimes(1)
Is this not an implementation detail? Should I really care if a function called "onSubmit" is being called? What if tomorrow it changes to "onFormSubmit"? Or what if the function is empty? The test would still pass...
Shouldn't we test instead if whatever onSubmit is supposed to do, is done? Like check if a DOM element changes or something...
I swear, it's being a real trip trying to grasp the art of writing tests (in general, not just in React).
If you want to avoid testing every implementation detail and only test the things a user cares about, you would need to do an end-to-end test with a tool like Cypress against a real backend and real database. The realism of these tests have a lot of value. But there are downsides as well: they can be slow and less reliable, so it isn't realistic to fully cover all code paths of a large application with them.
As soon as you drop down to component tests, you are already testing some things the user doesn't care about: if you pass props to the component or mock out a backend, the user doesn't care about those props or backend API. But it's a worthwhile tradeoff because it allows you to have faster tests that cover more edge cases.
In component tests I would recommend testing the component's inputs and outputs. If an onSubmit function is defined inside your component's render function, then I would not run an assertion against it; that's definitely an implementationn detail. Instead, I would test the result of that function running. But if onSubmit is passed in as a prop of the function, then I would pass in a mock function and check that it was called, yes. If it's a function defined in another module, things get fuzzier: you can decide whether you want to mock that module or test against the real implementation of that function.
There are always tradeoffs in testing; the above are some of the things you can consider when deciding how to test a specific case.
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.
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.
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.
I use Composite WPF(Prism) and I am trying to unit test that my Controller does in fact subscribe to a Composite Event.
My subscription code looks as follows...
//Init Events.
this.eventAggregator.GetEvent<PlantTreeNodeSelectedEvent>().Subscribe(
ShowNodeDetails, ThreadOption.UIThread);
My unit testing code looks as follows (I use Moq as my Mocking Framework and Unity as my DI Framework)...
Mock<PlantTreeNodeSelectedEvent> eventBeingListenedTo = new Mock<PlantTreeNodeSelectedEvent>();
eventAggregatorMock.Setup(e => e.GetEvent<PlantTreeNodeSelectedEvent>()).Returns(eventBeingListenedTo.Object);
//Initialize the controller to be tested.
IPlantTreeController controllerToTest = container.Resolve<IPlantTreeController>();
//Verify.
eventBeingListenedTo.Verify(
e => e.Subscribe(It.IsAny<Action<string>>(), ThreadOption.UIThread));
This subscribe method IS being called (I've verified by running with the debugger), but the Verify always fails with "Invocation was not performed on the mock: e => e.Subscribe..."
Any idea what I am doing wrong?
In your code, it seems like the eventAggregatorMock instance is never used. I would guess that you need to register it with the container so that it is being used by controllerToTest.
You seem to be testing too much in your unit test. You shouldn't need a container, you should just create your controller providing mock dependencies, because you should only test 1 thing in a unit test (you don't need to test that the DI framework works, as it usually does ;-)). It will also ensure that you provide the correct mocks, now it is not clear from your code as Mark Seemann has pointed out in his answer.
You may try to setup a method call under question in the beginning. Sometimes it seems to help moq to verify the class appropriately. In this case you may also want to setup your mock behavior to be Strict in the constructor, so that you will get the test failed for other, unexpected calls to your mock.
eventBeingListenedTo.Setup(e => e.Subscribe(It.IsAny<Action<string>>(), ThreadOption.UIThread));
use a mocking aggregator like this (for Rhino.Mocks)
http://adammills.wordpress.com/2010/12/13/auto-mocking-eventaggregator/
If you use ThreadOption.UIThread, it calls Dispatcher.Invoke which won't work without a Message Loop; which isn't normally running in unit tests.