Sort is not a function; spyOn not mocking - unit-testing

So I have a function with a sort that I am trying to unit test with Jasmine.
loadData() {
this.Service.getAll().subscribe(res => {
res.sort((x) => {
return x.Name, x.Id
});
this.stuff = res;
});
}
From what I have found, because the sort is an array.Prototype, I need to add a spyon the method. I have tried both of the following, but they don't handle it:
spyOn(Array.prototype,'sort').and.callThrough();
spyOn(Array.prototype,'sort');
I'm new to Jasmine, So I assume I am just missing something obvious. How do I handle this?
Thanks

It's a bad idea to spy on a prototype, you should spy on an instance instead. Take a look at this post. Actually, you are trying to test the method implementation, but you should test the class API instead. When you use a class, you don't think about its implementation, usually you even don't know how the class is implemented, it's just a black box. You should test the class the same way, otherwise it will be hard to maintain such tests, you'll have to update tests each time the implementation is changed. The loadData() method changes the object state somehow, just check that the state is changed correctly.

Related

Sinon stub instance method declared in mapDispatchToProps

New to testing and React Redux, so I may be conflating a few issues here. I will only present one example, but I have tried many different combinations of mount(), shallow(), instance(), stub, spy and more.
Given a component, where setFooData() updates redux state and Foo.props.data:
const mapDispatchToProps = (dispatch, props) => ({
setFooData(fooId, data) {
dispatch(Actions.setFooData(fooId, data));
},
});
...
return (
<div fooId={this.props.fooId}>
<Foo {...fooProps}/>
</div>
);
I would like to write some tests around the conditions under which setFooData() is called, namely conditions in lifecycle methods like componentDidMount() and componentWillReceiveProps().
Because setFooData() involves server calls and more, and because these tests merely concern the view layer and how the component renders as a result of Foo.props.data being set eventually by setFooData(), setFooData() seems like a good candidate for stub.
Therefore, Enzyme's shallow(), rather than mount(), seems appropriate, correct? In any case, when I try to stub setFooData():
let wrapper = return shallow(<Foo {...props}/>);
let stub = sinon.stub(wrapper.instance(), 'setFooData');
I receive the error:
Attempted to wrap undefined property setFooData as function
Upon inspection, wrapper.instance() yields an object where setFooData() is indeed not defined, but according to other examples, I would think it should be.
Furthermore, setFooData() does exist on wrapper.instance().selector.props, and while let stub = sinon.stub(wrapper.instance().selector.props, 'setFooData'); avoids the error, when I inspect the object setFooData() =/= stub, and the function is not called as per the test.
When I use mount() instead,
let wrapper = mount(<Provider store={store}><Foo {...props}/></Provider>);
let componentDidMountSpy = sinon.spy(Foo.prototype, 'componentDidMount');
let componentWillReceivePropsSpy = sinon.spy(Foo.prototype, 'componentWillReceiveProps');
expect(componentDidMountSpy.called).to.be.true; //passes
expect(componentWillReceivePropsSpy.called).to.be.true; //passes
expect(stub.called).to.be.true; //fails
I receive a different error that appears related to the body of setFooData(), so setFooData() is called but the function is not actually stubbed to prevent its real body from being executed.
Thanks for any help to clarify my understanding.
I think you're taking the hardest path. You should test your component in isolation, not the connected one. If you test the connected component you're making an integration test and double testing that connect indeed works. That's already tested in react-redux for you.
Instead, test your action creators by themselves in unit tests.
Then, export your component as named export without connecting and use the default export for the connect version.
That way you can simply import the pure-React version and pass anything you want as props, in order to make easy assertions afterwards.
If you need to specifically test that something happens in those lifecycle methods, you can call those methods from the instance:
const fakeActionCreator = sinon.spy()
const subject = mount(<MyComponent doSomething={ fakeActionCreator } />)
subject.instance().componentDidMount()
assert.equal(fakeActionCreator.callCount, 1)

How to test routes in Laravel 5, or Trying to "MockStub" something, or I have no idea of TDD

I'm starting with TDD and Laravel. Specifically, I'm starting with routes. I defined some and I defined it badly, so excited as I was with the "new" concept of TDD I wanted to write some test for them.
The idea was to test the routes and only the routes, in isolation, as everything I've readed about TDD recomends. I know I can do a $this->call->('METHOD','something') and test response is OK or whatever, but I would like to know that the right method of the right controller is called.
So, I thought that I could mock the controller. This was my first attempt:
public function test_this_route_work_as_expected_mocking_the_controller()
{
//Create the mock
$drawController = \Mockery::mock('App\Http\Controllers\DrawController');
$drawController->shouldReceive('show')->once();
// Bind instance of my controller to the mock
App::instance('App\Http\Controllers\DrawController', $drawController);
$response = $this->call('GET','/draw/1');
// To see what fails. .env debugging is on
print($response);
}
The route is Route::resource('draw', 'DrawController');, I know it's ok. But method show is not called. In the response it can be seen: "Method Mockery_0_App_Http_Controllers_DrawController::getAfterFilters() does not exist on this mock object". So I tried to:
$drawController->getAfterFilters()->willReturn(array());
But I get:
BadMethodCallException: Method Mockery_0_App_Http_Controllers_DrawController::getAfterFilters() does not exist on this mock object
After some testing, I was able to arrive to this solution:
public function test_this_route_work_as_expected_mocking_the_controller_workaround()
{
//Create the mock
$drawController = \Mockery::mock('App\Http\Controllers\DrawController');
// These are the methods I would like to 'stub' in this mock
$drawController->shouldReceive('getAfterFilters')->atMost(1000)->andReturn(array());
$drawController->shouldReceive('getBeforeFilters')->atMost(1000)->andReturn(array());
$drawController->shouldReceive('getMiddleware')->atMost(1000)->andReturn(array());
// This is where the corresponding method is called. I can assume all is OK if we arrive here with
// the right method name:
// public function callAction($method, $parameters)
$drawController->shouldReceive('callAction')->once()->with('show',Mockery::any());
// Bind instance of my controller to the mock
App::instance('App\Http\Controllers\DrawController', $drawController);
//Act
$response = $this->call('GET','/draw/1');
}
But I would like to change the shouldReceives for willReturns: the atMost(1000) are hurting my eyes. So the questions I have are:
1) Is there a cleaner way to test ONLY the routes in Laravel 5? I mean, the ideal scenario will be one in which the controller doesn't exist but, if the route is ok, the test pases
2) Is it possible to "MockStub" the controllers? What's the better way to do it?
Thank you very much.
I've finally got it. You need a partial mock. It can be done as simple as this (the trick is including an "array" of methods to mock to Mockery::mock):
public function test_this_route_work_as_expected_mocking_partially_the_controller()
{
//Create the mock
$drawController = \Mockery::mock('App\Http\Controllers\DrawController[show]');
$drawController->shouldReceive('show')->once();
// Bind instance of my controller to the mock
App::instance('App\Http\Controllers\DrawController', $drawController);
//Act
$this->call('GET','/draw/1');
}
And, if you create a partial mock of all controllers in setup() method, all route tests can be grouped in a single (or a couple) of TestCases

Private method Unit testing with Jasmine

I was coding test cases for an angular application using jasmine. But many internal methods are declared as private in the services.
Example:
App.service('productDisplay', function(){
var myPrivate = function(){
//do sth
}
this.doOfferCal = function(product, date){
//call myPrivate
//do sth too
return offer;
}
});
Using jasmine it straightforward to code test for "doOfferCal" but I want to write unit test for myPrivate too.
How can I do it?
Thanks in advance.
Thanks jabko87.
In addition, if you want to pass the the arguments use the below example:
const myPrivateSpy = spyOn<any>(service, 'transformNative').and.callThrough();
myPrivateSpy.call(service, {name: 'PR'});
Note: Here service is the Class, transformNative is the private method and {name: 'PR'} passing an object argument
Is there a specific reason you wish to test your private methods?
By testing doOfferCal(), you're implicitly testing that myPrivate() is doing the right thing.
Though this is for RailsConf, Sandi Metz has a very good talk on what should be tested.
Achan is 100% right, but if you really need to call private method in your tests (what should be never :-) ) you can do it by:
var myPrivateSpy = spyOn(productDisplayService, "myPrivate").and.callThrough();
myPrivateSpy.call();
If you want to call your private method you just have to do it like this:
component["thePrivateMethodName"](parameters);
Where component is your service class or component class.
To test inner functions I call the outer function that calls the inner function and then vary my input according to what the inner function requires. So, in your case you would call productDisplay and vary your input based upon what myPrivate needs and then verify that you have the expected output. You could also spy on myPrivate and test things that way using .havebeencalledwith or .andcallthrough.

Unit testing against repositories, with MSpec, am I doing this right?

A second MSpec question from me in a day, this is a new record. I'm trying to get smart on MSpec very quickly and I've run into some old problems I've always had with MSpec.
Scenario: I have a repository that contains a bunch of cartoons. Right now I only need to filter this set on a single Name parameter, which is a string. As I'm told I'll need to filter this on more properties later on, I decide to create a class which takes in my ICartoonRepository via IoC, and contains a simple method that's called GetByName(string name).
You might argue this is overkill, but I'm trying to teach myself how to use MSpec and work in a more TDD manner.
So I create the following:
[Subject(typeof(CartoonViewModelBuilder))]
public class when_cartoon_repository_is_asked_to_get_by_id : specification_for_cartoon_viewmodel_builder
{
static string name;
static Cartoon the_cartoon;
static Cartoon result;
Establish context = () =>
{
name = "Taz";
the_cartoon = new Cartoon();
the_cartoon_repository.Stub(r => r.GetAll().Where(x=>x.Name == name).FirstOrDefault()).Return(the_cartoon);
};
Because of = () => result = subject.GetByName(name);
It should_return_cartoon = () => result.ShouldBeTheSameAs(the_cartoon);
}
This fails on the stub as the repository is empty. I have a couple other tests that pass fine (simply testing the GetAll(), etc). Do I need to add things to the repository to test it? This is where I'm stumped, please be gentle.
Also, if I'm writing the linq statement in the stub, it seems like I'm doing it twice, in the actual implementation and in the test. Is this the point? It doesn't feel right. Is there a better way I can write this test?
For clarity sake, here is the actual implementation (I'm omitting the interface and the class, which just has one property:
public class CartoonViewModelBuilder: ICartoonViewModelBuilder
{
readonly ICartoonRepository _cartoonRepository;
public CartoonQueryObject(ICartoonRepository cartoonRepository)
{
_cartoonRepository = cartoonRepository;
}
public IList<Cartoon> GetAllCartoons()
{
return _cartoonRepository.GetAll();
}
public Cartoon GetByName(string name)
{
return _cartoonRepository.GetAll().Where(x => x.Name == name).FirstOrDefault();
}
}
Edit 1: Based on the lack of responses, I should say that if I were using something like NUnit, I would be creating a method on the testing class that was like, "LoadDummyData" and threw data into the repository, then I'd do complex filtering or view model building and sort of manually checked what happened. This made large refactoring a chore. It seems like specs allows you to avoid that?
Edit 2: Here's my corrected test which now passes. Let me know if I'm doing it right, I think I am. Thanks again for the hand holding!
static string name;
static Cartoon the_cartoon;
static Cartoon result;
static IQueryable<Cartoon> the_cartoons;
Establish context = () =>
{
name = "Taz";
the_cartoon = new Cartoon {Name = name};
the_cartoons = new List<Cartoon> {the_cartoon, new Cartoon(), new Cartoon() }.AsQueryable();
the_cartoon_repository.Stub(r => r.GetAll()).Return(the_cartoons.ToList());
};
Because of = () => result = subject.GetByName(name);
It should_return_cartoon = () => result.ShouldBeTheSameAs(the_cartoon);
Edit 3: Gave you both points, but I can only award one best answer unfortunately.
The actual reason of this test failing is the way you're mocking your repository. I would be very surprised if method chains like r.GetAll().Where(x=>x.Name == name).FirstOrDefault() could be mocked so easily, as it uses LINQ extension methods and lambda clauses. The framework should really throw NotSupported exception or something to let you know that you can't mock LINQ queries as a whole.
To mock LINQ query result, you should provide properly prepared underlying data collection, which is the starting point of LINQ query. In your example you should mock just r.GetAll() to return a collection containing your element with proper name. The actual query will run on your "mocked" data and retrieve the object you expect.
This removes the need to duplicate your LINQ query in code and in test, what is strange, as you noted.
EDIT: Code in your edit is like I've suggested, technically OK.
Anyway, by now it's a bit overkill, as you've said. Your class under test doesn't do anything beside the call to the mocked repository, so the value of that test is rather small. But it may be a good start if you're going to have some more logic in GetByName method.
If you want to test your repository implementation, don't stub it! MSpec or not, I would add a list of known items to the repository and then issue the query with GetByName. Then assert that just the item you expect was returned. I would also use ShouldEqual as the repository might work with the items you add and return a different instance, though considered equal (aggregate IDs are equal).

How do you organise your MVC controller tests?

I'm looking for tidy suggestions on how people organise their controller tests.
For example, take the "add" functionality of my "Address" controller,
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult Add()
{
var editAddress = new DTOEditAddress();
editAddress.Address = new Address();
editAddress.Countries = countryService.GetCountries();
return View("Add", editAddress);
}
[RequireRole(Role = Role.Write)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Add(FormCollection form)
{
// save code here
}
I might have a fixture called "when_adding_an_address", however there are two actions i need to test under this title...
I don't want to call both actions in my Act() method in my fixture, so I divide the fixture in half, but then how do I name it?
"When_adding_an_address_GET" and "When_adding_an_address_POST"?
things just seems to be getting messy, quickly.
Also, how do you deal with stateless/setupless assertions for controllers, and how do you arrange these wrt the above? for example:
[Test]
public void the_requesting_user_must_have_write_permissions_to_POST()
{
Assert.IsTrue(this.SubjectUnderTest.ActionIsProtectedByRole(c => c.Add(null), Role.Write));
}
This is custom code i know, but you should get the idea, it simply checks that a filter attribute is present on the method. The point is it doesnt require any Arrange() or Act().
Any tips welcome!
Thanks
In my opinion you should forget about naming your tests after the methods you're testing. In fact testing a single method is a strange concept. You should be testing a single thing a client will do with your code. So for example if you can hit add with a POST and a GET you should write two tests like you suggested. If you want to see what happens in a certain exceptional case you should write another test.
I usually pick names that tell a maintainer what he needs to know in Java:
#Test public void shouldRedirectToGetWhenPostingToAdd(){
//...
}
You can do this in any language and pick any *DD naming convention if you like, but the point is that the test name should convey the expectations and the scenario. You will get very small test this way and I consider this a good thing.
Well, 13 months later and no answers. Awesome.
Heres what i do now:
/tests/controllers/address/add/get.cs
/tests/controllers/address/add/valid.cs
/tests/controllers/address/add/invalid.cs