tl;dr is it possible to unit test this code without rewriting it?
http://jsbin.com/jezosegopo/edit?js,console
const keyUpObserver = ($input, fetchResults) => {
const source = Rx.Observable.fromEvent($input, 'keyup')
.map(e => e.target.value)
.filter(text => text.length > 2)
.debounce(300)
.distinctUntilChanged();
return source.flatMapLatest(text => Rx.Observable.fromPromise(fetchResults(text)));
};
keyUpObserver in the above code is heavily based on the RxJS autocomplete example, and uses a debounce to prevent hammering the server.
I'm trying to unit test this function, but Sinon's useFakeTimers doesn't appear to be working.
const clock = sinon.useFakeTimers();
const $input = $('<input>');
const fetchResults = (text) => new Promise(resolve => resolve(text + ' done!'));
keyUpObserver($input, fetchResults).subscribe(text => console.log(text));
$input.val('some text').trigger('keyup');
clock.tick(500);
// Enough time should have elapsed to make this a new event
$input.val('some more text').trigger('keyup');
I'm guessing this isn't sinon-related either, rather that RxJS uses some internal clock which must be unaffected by an external fake clock.
Given that, is there anyway to unit test my keyUpObserver code without rewriting it to also take a scheduler (default in production, test in unit tests)?
...to approach an answer: it seems that RxJs is using the default/global setTimeout implementation which Sinon should be able to overwrite. At least that's what I'd say from reading the defiultscheduler's code which it uses if you don't pass (as mentioned) an custom scheduler.
Still, I am a bit confused about the intend. From this little fork I'd expect only the 3rd trigger to actually fire something which it does or am I should out of line? 👀
Related
I know mocha has global before and after, and each-test before and after, but what I would like is test-specific before and after. Something like SoapUI has.
For example, say that I have a test checking that the creation of a user works.
I want to remove the user, should it exist, from the database BEFORE the test. And I want the test to ensure that the user is removed AFTER the test. But I do not want to do this for EACH test, as only one test will actually create the user. Other tests will delete user/s, update user/s, fail to create an already existing user etc.
Is this possible, or do I have to include the setup and tear down code in the test? If so, how do I ensure that both the setup and tear down executes properly, independent of the test result?
For tests where I need to have special setup and teardown code but that are not otherwise distinguishable from their siblings, I just put a describe block with an empty title:
describe("SomeClass", () => {
describe("#someMethod", () => {
it("does something", () => {});
it("does something else", () => {});
describe("", () => {
// The before and after hooks apply only to the tests in
// this block.
before(() => {});
after(() => {});
it("does something more", () => {});
});
});
});
Is this possible, or do I have to include the setup and tear down code in the test? If so, how do I ensure that both the setup and tear down executes properly, independent of the test result?
You can put setup and tear down code in the test itself (i.e. inside an the callback you pass to it). However, Mocha will treat any failure there as a failed test, period. It does not matter where in the callback passed to it the failure occurs. Assertion libraries allow you to provide custom error messages which can help you figure out what exactly failed, but Mocha will see all failures in it the same way: the test failed. If you want Mocha to treat failures in setup/teardown code differently from test failures, then you have to use the hooks as I've shown above.
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)
Has someone worked on unit testing ag-grid components in Angular 2?
For me, this.gridOptions.api remains undefined when the test cases run.
Sorry to be a little late to the party but I was looking for an answer to this just a couple of days ago so wanted to leave an answer for anyone else that ends up here. As mentioned by Minh above, the modern equivalent of $digest does need to be run in order for ag-grid api's to be available.
This is because after the onGridReady() has run you have access to the api's via the parameter, looking like so. This is run automatically when a component with a grid is initialising. Providing it is defined in the grid (gridReady)="onGridReady($event)"
public onGridReady(params)
{
this.gridOptions = params;
}
This now means you could access this.gridOptions.api and it would be defined, you need to re-create this in your test by running detectChanges(). Here is how I got it working for my project.
fixture = TestBed.createComponent(TestComponent);
component = fixture.componentInstance;
fixture.detectChanges(); // This will ensure the onGridReady(); is called
This should inturn result in .api being defined when running tests. This was Angular 6.
Occasionally the test may have to perform an await or a tick:
it('should test the grid', fakeAsync( async () => {
// also try tick(ms) if a lot of data is being tested
// try to keep test rows as short as possible
// this line seems essential at times for onGridReady to be processed.
await fixture.whenStable();
// perform your expects...after the await
}));
If you are using ag-grid enterprise make sure to include in your test file import 'ag-grid-enterprise'; otherwise you will see console errors and gridReady will never be called:
Row Model "Server Side" not found. Please ensure the ag-Grid Enterprise Module #ag-grid-enterprise/server-side-row-model is registered.';
It remains undefined because the event onGridReady is not invoked yet. Im not sure about Angular 2 because im using angularjs and have to do $digest in order to invoke onGridReady.
I'm having trouble testing reactive code that's consuming a Task based service. In my class under test I consume the task and use ToObservable to do reactive-y things with it.
public void Method()
{
_svc.MyTaskServiceMethod().ToObservable().Select(....) //pipe it elsewhere and do interesting things.
}
Now in a unit test I'm testing some timing (using Moq for the service)
svcMock.Setup(x => x.MyTaskServiceMethod()).Returns(() =>
Observable.Return("VALUE", testScheduler)
.Delay(TimeSpan.FromMilliseconds(100), testScheduler)
.ToTask()
);
The problem is that despite using the test scheduler in the Return/Delay calls, the task itself is still completing on a separate thread. I'm seeing this by adding a couple of Console writes of the current managed thread id to the code.
svcMock.Setup(x => x.MyServiceMethod()).Returns(() =>
{
var task = Observable.Return("VALUE", testScheduler)
.Delay(TimeSpan.FromMilliseconds(1000), testScheduler)
.Do(x => { Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + " Obs"); })
.ToTask();
task.ContinueWith((_) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + " Task");
});
return task;
});
The Do(..) executes on the primary testing thread, and happens exactly when I expect after a testSchduler.AdvanceBy(..) call.
The task continuation is still happening in a separate thread and basically doesn't execute until after the body of the unit test has finished. So in the body of my target, nothing ever really gets pushed through my task.ToObservable() observable.
Task continuations will use a task pool thread by default, so your continuation escapes the control of the test scheduler. If you specify the option TaskContinuationOptions.ExecuteSynchronously, it will use the same thread and the result will be posted to the observable as desired:
task.ContinueWith((_) =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId.ToString() + " Task");
}, TaskContinuationOptions.ExecuteSynchronously);
Addendum
You may find this related discussion on the Rx site quite illuminating on the subject of concurrency in TPL -> Rx transitions, and ToObservable() in particular.
Some time ago I co-authored a unit test library based on NUnit to help with precisely with Rx and TPL testing. For that we built a Test TPL scheduler to force all TPL tasks to run without concurrency. You can see the relevant code here: https://github.com/Testeroids/Testeroids/blob/master/solution/src/app/Testeroids/TplTestPlatformHelper.cs#L87
I've got a bunch of methods in my application service layer that are doing things like this:
public void Execute(PlaceOrderOnHoldCommand command)
{
var order = _repository.Load(command.OrderId);
order.PlaceOnHold();
_repository.Save(order);
}
And at present, I have a bunch of unit tests like this:
[Test]
public void PlaceOrderOnHold_LoadsOrderFromRepository()
{
var repository = new Mock<IOrderRepository>();
const int orderId = 1;
var order = new Mock<IOrder>();
repository.Setup(r => r.Load(orderId)).Returns(order.Object);
var command = new PlaceOrderOnHoldCommand(orderId);
var service = new OrderService(repository.Object);
service.Execute(command);
repository.Verify(r => r.Load(It.Is<int>(x => x == orderId)), Times.Exactly(1));
}
[Test]
public void PlaceOrderOnHold_CallsPlaceOnHold()
{
/* blah blah */
}
[Test]
public void PlaceOrderOnHold_SavesOrderToRepository()
{
/* blah blah */
}
It seems to be debatable whether these unit tests add value that's worth the effort. I'm quite sure that the application service layer should be integration tested, though.
Should the application service layer be tested to this level of granularity, or are integration tests sufficient?
I'd write a unit test despite there also being an integration test. However, I'd likely make the test much simpler by eliminating the mocking framework, writing my own simple mock, and then combining all those tests to check that the the order in the mock repository was on hold.
[Test]
public void PlaceOrderOnHold_LoadsOrderFromRepository()
{
const int orderId = 1;
var repository = new MyMockRepository();
repository.save(new MyMockOrder(orderId));
var command = new PlaceOrderOnHoldCommand(orderId);
var service = new OrderService(repository);
service.Execute(command);
Assert.IsTrue(repository.getOrder(orderId).isOnHold());
}
There's really no need to check to be sure that load and/or save is called. Instead I'd just make sure that the only way that MyMockRepository will return the updated order is if load and save are called.
This kind of simplification is one of the reasons that I usually don't use mocking frameworks. It seems to me that you have much better control over your tests, and a much easier time writing them, if you write your own mocks.
Exactly: it's debatable! It's really good that you are weighing the expense/effort of writing and maintaining your test against the value it will bring you - and that's exactly the consideration you should make for every test you write. Often I see tests written for the sake of testing and thereby only adding ballast to the code base.
As a guideline I usually take that I want a full integration test of every important successful scenario/use case. Other tests I'll write are for parts of the code that are likely to break with future changes, or have broken in the past. And that is definitely not all code. That's where your judgement and insight in the system and requirements comes into play.
Assuming that you have an (integration) test for service.Execute(placeOrderOnHoldCommand), I'm not really sure if it adds value to test if the service loads an order from the repository exactly once. But it could be! For instance when your service previously had a nasty bug that would hit the repository ten times for a single order, causing performance issues (just making it up). In that case, I'd rename the test to PlaceOrderOnHold_LoadsOrderFromRepositoryExactlyOnce().
So for each and every test you have to decide for yourself ... hope that helps.
Notes:
The tests you show can be perfectly valid and look well written.
Your test sequence methods seems to be inspired on the way the Execute(...) method is currently implemented. When you structure your test this way, it could be that you are tying yourself to a specific implementation. This way, tests can actually make it harder to change - make sure you're only testing the important external behavior of your class.
I usually write a single integration test of the primary scenario. By primary scenario i mean the successful path of all the code being tested. Then I write unit tests of all the other scenarios like checking all the cases in a switch, testing exception and so forth.
I think it is important to have both and yes it is possible to test it all with integration tests only, but that makes your tests long running and harder to debug. In average I think I have 10 unit tests per integration test.
I don't bother to test methods with one-liners unless something bussines logic-like happens in that line.
Update: Just to make it clear, cause I'm doing test-driven development I always write the unit tests first and typically do the integration test at the end.