How to test my controllers? - javascript

I am using Express to build a REST API. The code is divided, as should be, in Routes/Models/Controllers (no views, it's just JSON)
The controllers take care of the logic : they make request to the database and build the responses. To me, this is the main thing to test in my application.
Now, how should I test my controllers ?
I have read that writing atomic tests is the best way to go, so I guess I should clear the database, run migrations and seed the database before every single test (which is composed of making a request to the controller + checking the response)... but this takes ages, even for a very small number of tests ! If I do it this way, hooking the tests to git seems a really bad idea, and the whole idea of testing them breaks down.

You can test your REST API using Postman.

Related

Why do we use mockImplementation instead of using actual function which we need to test? [duplicate]

What is Mocking?                                                                                                    .
Prologue: If you look up the noun mock in the dictionary you will find that one of the definitions of the word is something made as an imitation.
Mocking is primarily used in unit testing. An object under test may have dependencies on other (complex) objects. To isolate the behaviour of the object you want to test you replace the other objects by mocks that simulate the behaviour of the real objects. This is useful if the real objects are impractical to incorporate into the unit test.
In short, mocking is creating objects that simulate the behaviour of real objects.
At times you may want to distinguish between mocking as opposed to stubbing. There may be some disagreement about this subject but my definition of a stub is a "minimal" simulated object. The stub implements just enough behaviour to allow the object under test to execute the test.
A mock is like a stub but the test will also verify that the object under test calls the mock as expected. Part of the test is verifying that the mock was used correctly.
To give an example: You can stub a database by implementing a simple in-memory structure for storing records. The object under test can then read and write records to the database stub to allow it to execute the test. This could test some behaviour of the object not related to the database and the database stub would be included just to let the test run.
If you instead want to verify that the object under test writes some specific data to the database you will have to mock the database. Your test would then incorporate assertions about what was written to the database mock.
Other answers explain what mocking is. Let me walk you through it with different examples. And believe me, it's actually far more simpler than you think.
tl;dr It's an instance of the original class. It has other data injected into so you avoid testing the injected parts and solely focus on testing the implementation details of your class/functions.
Simple example:
class Foo {
func add (num1: Int, num2: Int) -> Int { // Line A
return num1 + num2 // Line B
}
}
let unit = Foo() // unit under test
assertEqual(unit.add(1,5),6)
As you can see, I'm not testing LineA ie I'm not validating the input parameters. I'm not validating to see if num1, num2 are an Integer. I have no asserts against that.
I'm only testing to see if LineB (my implementation) given the mocked values 1 and 5 is doing as I expect.
Obviously in the real word this can become much more complex. The parameters can be a custom object like a Person, Address, or the implementation details can be more than a single +. But the logic of testing would be the same.
Non-coding Example:
Assume you're building a machine that identifies the type and brand name of electronic devices for an airport security. The machine does this by processing what it sees with its camera.
Now your manager walks in the door and asks you to unit-test it.
Then you as a developer you can either bring 1000 real objects, like a MacBook pro, Google Nexus, a banana, an iPad etc in front of it and test and see if it all works.
But you can also use mocked objects, like an identical looking MacBook pro (with no real internal parts) or a plastic banana in front of it. You can save yourself from investing in 1000 real laptops and rotting bananas.
The point is you're not trying to test if the banana is fake or not. Nor testing if the laptop is fake or not. All you're doing is testing if your machine once it sees a banana it would say not an electronic device and for a MacBook Pro it would say: Laptop, Apple. To the machine, the outcome of its detection should be the same for fake/mocked electronics and real electronics. If your machine also factored in the internals of a laptop (x-ray scan) or banana then your mocks' internals need to look the same as well. But you could also use a MacBook that no longer works.
Had your machine tested whether or not devices can power on then well you'd need real devices.
The logic mentioned above applies to unit-testing of actual code as well. That is a function should work the same with real values you get from real input (and interactions) or mocked values you inject during unit-testing. And just as how you save yourself from using a real banana or MacBook, with unit-tests (and mocking) you save yourself from having to do something that causes your server to return a status code of 500, 403, 200, etc (forcing your server to trigger 500 is only when server is down, while 200 is when server is up.
It gets difficult to run 100 network focused tests if you have to constantly wait 10 seconds between switching over server up and down). So instead you inject/mock a response with status code 500, 200, 403, etc and test your unit/function with a injected/mocked value.
Be aware:
Sometimes you don't correctly mock the actual object. Or you don't mock every possibility. E.g. your fake laptops are dark, and your machine accurately works with them, but then it doesn't work accurately with white fake laptops. Later when you ship this machine to customers they complain that it doesn't work all the time. You get random reports that it's not working. It takes you 3 months to figure out that the color of fake laptops need to be more varied so you can test your modules appropriately.
For a true coding example, your implementation may be different for status code 200 with image data returned vs 200 with image data not returned. For this reason it's good to use an IDE that provides code coverage e.g. the image below shows that your unit-tests don't ever go through the lines marked with brown.
image source
Real world coding Example:
Let's say you are writing an iOS application and have network calls.Your job is to test your application. To test/identify whether or not the network calls work as expected is NOT YOUR RESPONSIBILITY . It's another party's (server team) responsibility to test it. You must remove this (network) dependency and yet continue to test all your code that works around it.
A network call can return different status codes 404, 500, 200, 303, etc with a JSON response.
Your app is suppose to work for all of them (in case of errors, your app should throw its expected error). What you do with mocking is you create 'imaginary—similar to real' network responses (like a 200 code with a JSON file) and test your code without 'making the real network call and waiting for your network response'. You manually hardcode/return the network response for ALL kinds of network responses and see if your app is working as you expect. (you never assume/test a 200 with incorrect data, because that is not your responsibility, your responsibility is to test your app with a correct 200, or in case of a 400, 500, you test if your app throws the right error)
This creating imaginary—similar to real is known as mocking.
In order to do this, you can't use your original code (your original code doesn't have the pre-inserted responses, right?). You must add something to it, inject/insert that dummy data which isn't normally needed (or a part of your class).
So you create an instance the original class and add whatever (here being the network HTTPResponse, data OR in the case of failure, you pass the correct errorString, HTTPResponse) you need to it and then test the mocked class.
Long story short, mocking is to simplify and limit what you are testing and also make you feed what a class depends on. In this example you avoid testing the network calls themselves, and instead test whether or not your app works as you expect with the injected outputs/responses —— by mocking classes
Needless to say, you test each network response separately.
Now a question that I always had in my mind was: The contracts/end points and basically the JSON response of my APIs get updated constantly. How can I write unit tests which take this into consideration?
To elaborate more on this: let’s say model requires a key/field named username. You test this and your test passes.
2 weeks later backend changes the key's name to id. Your tests still passes. right? or not?
Is it the backend developer’s responsibility to update the mocks. Should it be part of our agreement that they provide updated mocks?
The answer to the above issue is that: unit tests + your development process as a client-side developer should/would catch outdated mocked response. If you ask me how? well the answer is:
Our actual app would fail (or not fail yet not have the desired behavior) without using updated APIs...hence if that fails...we will make changes on our development code. Which again leads to our tests failing....which we’ll have to correct it. (Actually if we are to do the TDD process correctly we are to not write any code about the field unless we write the test for it...and see it fail and then go and write the actual development code for it.)
This all means that backend doesn’t have to say: “hey we updated the mocks”...it eventually happens through your code development/debugging. ‌ّBecause it’s all part of the development process! Though if backend provides the mocked response for you then it's easier.
My whole point on this is that (if you can’t automate getting updated mocked API response then) human interaction is likely required ie manual updates of JSONs and having short meetings to make sure their values are up to date will become part of your process
This section was written thanks to a slack discussion in our CocoaHead meetup group
Confusion:
It took me a while to not get confused between 'unit test for a class' and the 'stubs/mocks of a class'.
E.g. in our codebase we have:
class Device
class DeviceTests
class MockDevice
class DeviceManager
class Device is the actual class itself.
class DeviceTests is where we write unit-tests for the Device class
class MockDevice is a mock class of Device. We use it only for the purpose of testing. e.g. if our DeviceManager needs to get unit-tested then we need dummy/mock instances of the Device class. The MockDevice can be used to fulfill the need of dummy/mock instances.
tldr you use mock classes/objects to test other objects. You don't use mock objects to test themselves.
For iOS devs only:
A very good example of mocking is this Practical Protocol-Oriented talk by Natasha Muraschev. Just skip to minute 18:30, though the slides may become out of sync with the actual video 🤷‍♂️
I really like this part from the transcript:
Because this is testing...we do want to make sure that the get function
from the Gettable is called, because it can return and the function
could theoretically assign an array of food items from anywhere. We
need to make sure that it is called;
There are plenty of answers on SO and good posts on the web about mocking. One place that you might want to start looking is the post by Martin Fowler Mocks Aren't Stubs where he discusses a lot of the ideas of mocking.
In one paragraph - Mocking is one particlar technique to allow testing of a unit of code with out being reliant upon dependencies. In general, what differentiates mocking from other methods is that mock objects used to replace code dependencies will allow expectations to be set - a mock object will know how it is meant to be called by your code and how to respond.
Your original question mentioned TypeMock, so I've left my answer to that below:
TypeMock is the name of a commercial mocking framework.
It offers all the features of the free mocking frameworks like RhinoMocks and Moq, plus some more powerful options.
Whether or not you need TypeMock is highly debatable - you can do most mocking you would ever want with free mocking libraries, and many argue that the abilities offered by TypeMock will often lead you away from well encapsulated design.
As another answer stated 'TypeMocking' is not actually a defined concept, but could be taken to mean the type of mocking that TypeMock offers, using the CLR profiler to intercept .Net calls at runtime, giving much greater ability to fake objects (not requirements such as needing interfaces or virtual methods).
Mock is a method/object that simulates the behavior of a real method/object in controlled ways. Mock objects are used in unit testing.
Often a method under a test calls other external services or methods within it. These are called dependencies. Once mocked, the dependencies behave the way we defined them.
With the dependencies being controlled by mocks, we can easily test the behavior of the method that we coded. This is Unit testing.
What is the purpose of mock objects?
Mocks vs stubs
Unit tests vs Functional tests
Mocking is generating pseudo-objects that simulate real objects behaviour for tests
The purpose of mocking types is to sever dependencies in order to isolate the test to a specific unit. Stubs are simple surrogates, while mocks are surrogates that can verify usage. A mocking framework is a tool that will help you generate stubs and mocks.
EDIT: Since the original wording mention "type mocking" I got the impression that this related to TypeMock. In my experience the general term is just "mocking". Please feel free to disregard the below info specifically on TypeMock.
TypeMock Isolator differs from most other mocking framework in that it works my modifying IL on the fly. That allows it to mock types and instances that most other frameworks cannot mock. To mock these types/instances with other frameworks you must provide your own abstractions and mock these.
TypeMock offers great flexibility at the expense of a clean runtime environment. As a side effect of the way TypeMock achieves its results you will sometimes get very strange results when using TypeMock.
I would think the use of the TypeMock isolator mocking framework would be TypeMocking.
It is a tool that generates mocks for use in unit tests, without the need to write your code with IoC in mind.
If your mock involves a network request, another alternative is to have a real test server to hit. You can use a service to generate a request and response for your testing.

What is the point of mocking the method of an external library when unit testing?

What is the point of mocking the method of an external library when unit testing?
Let's say that I have a function that uses XYZ library to get the current user using a given authorization token, and then if it finds the user, it returns a valid AWS policy:
export const getUser = async token => {
const user = await XYZ.getUser(token)
return {
// valid policy
context: user,
}
}
If an invalid token is given, the getUser should throw an error.
What is the point of testing this function if the XYZ.getUser is already well tested?
Why mock the getUser instead of using the real one?
You wouldn't want to invoke the actual HTTP request for XYZ.getUser(token), due to the following reasons.
1) The objective of unit testing is to test a specific behaviour, and in your very case, it is to test that your getUser function actually works.
2) You wouldn't want to make an actual request to the backend, as that would usually mean writing/reading/deleting something from the database. In many cases, it is not a good idea to overcomplicate your unit testing, as such operations should not be tested on the front-end, since you would want to limit and simplify your unit testing to test for a very specific behaviour.
3) Since the main objective is to test the above behaviour, you would want to simplify and limit what you are testing. As such, you will need to understand that unit testing of network requests of XYZ.getUser(token) should be done at the server-side, instead of client-side (or front-end).
4) By mocking the response from XYZ.getUser(token), we can simulate multiple scenarios and responses, such as successful responses (Code 200 OK), and other types of errors (business logic errors from the backend, or network errors such as error 400, 500, etc). You can do so by hardcoding the required JSON responses from XYZ.getUser(token) on the different types of scenarios you need to test.
this goes back to the definition and usages of unit tests.
Unit tests are supposed to test well defined functionality, for example you might write an algorithm and the functionality of that is very well defined. Then, because you know how it's supposed to function then you would unit test that.
Unit tests by definition, are not meant to touch any external systems, such as but not limited to files, APIs, databases, anything that requires going outside of the logical unit which is the code you want to test.
There are multiple reasons for that among which is execution speed. Calling an API, or using a third party call, takes a while. That's not necessary a problem when you look at one test, but when you have 500 tests or more then the delays will be important. The main idea is that you are supposed to run your unit tests all the time, very quickly, you get immediate feedback, is anything broken, have I broken something in other parts of the system. In any mature system you will run these tests as part of your CI/CD process and you cannot afford to wait too long for them to finish. no, they need to run in seconds, which is why you have the rules of what they should or should not touch.
You mock external things, to improve execution speed and eliminate third party issues as you really only want to test your own code.
What if you call a third party API and they are down for maintenance? Does that mean you can't test your code because of them?
Now, on the topic of mocking, do not abuse it too much, if you code in a functional way then you can eliminate the need for a lot of mocking. Instead of passing or har-coding dependencies, pass data. This makes it very easy to alter the input data without mocking much. You test the system as a while using integration / e2e tests, this gives you the certainty that your dependencies are resolved correctly.

Using NeDB for testing, while using other DBs in FeatherJS application

I'm wondering if it is common practice to use an in-memory database for a test environment, instead of MySQL (that has to be used for development/production).
If it makes sense, how do I set this up?
I think I can create config/test.json as shown in their chat example, my app.js still requires Knex though.
Should I do something along the lines of
const knex = (NODE_ENV !== 'test') ? require('./knex') : undefined;
and then configure it only if knex !== undefined?
If I do so, all my models have to be set up twice (once for Knex, once for testing without it).
What is the right/standard way to go about this?
EDIT:
As suggested below, I use a different schema for testing.
This is done by declaring a different connection string in config/test.json.
This question is solved, thank you!
if it is common practice to use an in-memory database for a test environment, instead
Sadly it is a common practise, but not particulary good one. When you use different database for testing and other for production your tests are actually not testing that the application code is working in real database.
Other negative effect is also that you cannot use special features of any of those databases, but the code would have to use that subset of DB features, which are supported by both of the databases.
I would ran all the tests with all the supported real databases to actually make sure that code works on every targeted setup.
ps. Someone was telling to use mocks for abstracting database... that is another bad practise. They work for some small part of testing, but in general case you need to run tests against real database to be sure that code works correctly. Important thing is to setup tests in a way that you have a fast way of truncating old data and populating new test data in.

Should I Unit Test For a Call to $.ajax or that an XHR has been sent?

Let's say I have the following method:
function sendUserDataToServer(userData) {
// Do some configuration stuff
$.ajax('SomeEndpoint', userData);
}
When writing a unit test for this function, I could go one of two ways:
Create a spy around $.ajax and check that it was called with the expected parameters. An actual XHR request will not be sent.
Intercept the ajax request with a library like SinonJs and check the XHR object to make sure it was configured correctly.
Why I might go with option 1: It separates the functionality of $.ajax from my code. If $.ajax breaks due to a bug in jQuery, it won't create a false-negative in my unit test results.
Why I might go with option 2: If I decide I want to use another library besides jQuery to send XHRs, I won't have to change my unit tests to check for a different method. However, if there's a bug in that library, my unit tests will fail and I won't necessarily know it's the library and not my actual code right away.
Which approach is correct?
Your first option is correct. The purpose of your unit test is twofold
to verify your code contract
to verify that it communicates with other things it uses.
Your question is about the interaction with $.ajax, so the purpose of this test is to confirm it can talk correctly to its collaborators.
If you go with option 1, this is exactly what you are doing. If you go with option 2, you're testing the third party library and not that you're executing the communication protocol correctly.
You should make both tests though. The second test is probably fast enough to live with your unit tests, even though some people might call it an integration test. This test tells you that you're using the library correctly to create the object you intended to create. having both will let you differentiate between a bug in your code and the library, which will come in handy if there is a library bug that causes something else in your system to fail.
My opinion: option 1 is more correct within unit tests.
A unit test should test the unit of code only. In your case this would be the JavaScript under your control (e.g. logic within the function, within a class or namespace depending on the context of your function).
Your unit tests should mock the jQuery call and trust that it works correctly. Doing real AJAX calls is fine, but these would be part of integration tests.
See this answer regarding what is and what isn't a unit test.
As an aside, a third way would be to do the AJAX calls via a custom proxy class which can be mocked in tests but also allows you to switch the library you use.
I would use option 1 but go with the one that makes the tests easiest to understand.
You are depending on jQuery in your code, so you don't need to worry about it actually working as you point out. I have found that it makes the tests cleaner as you specify your parameters and the response and have your code process it. You can also specify which callback should be used (success or error) easily.
As for changing the library from jQuery. If you change the code your test should fail. You could argue that your behavior is now different. Yes, you are making an Ajax call but with a different dependency. And your test should be updated to reflect this change.
Both approaches are really correct. If you are creating your own wrapper for sending Ajax calls, it might make sense to intercept the XHR request or manually creating the request and sending it yourself. Choose the option that makes your test easiest to understand and maintain.
the most important thing is to test your own code. separate business logic from the IO code and your business logic. after that you should have methods without any logic that do the actual IO (exactly as in your example). and now: should you test that method? it depends. tests are to make you feel safer.
if you really worry that jQuery can fail and you can't afford such unlikely scenario than test it. but not with some mocking library but do full end-to-end integration tests
if you're not sure if you are using jQuery correctly then do the 'learning tests'. pass a parameters to it and check what kind of request it produces. mocking tests should be enough in this situation
if you need a documentation of a contract between frontend and backend then you may choose if you prefer to test if backend meets the contract, frontend or both
but if none of above applies to you then isn't it a waste of time to test external, well established framework? jquery guys for sure have tested it. still you will probably need some kind of integration tests (automatic or manual) to check if your frontend interacts with backend properly. and those tests will cover the network layer

Jasmine test on mock data or on real-life systems and data sources?

I have a basic question about using Jasmine BDD. Are tests meant to be simulation done on "mock" data?
I want to make a test version of an existing script, which gets data from scroll events on a web page (this script is not done). But I see Jasmine makes use of SpecRunner.html and HTMLReporter to validate the tests in the UI.
How do I use this with my own web page?
Is BDD/TDD meant to be isolated simulations to test logic? Not really connecting it with real production systems and data sources..?
Trying to grasp the basics here :)
yes you want to use the Dependency Inversion Principle here. Basically you want your logic (alg) to have the DOM object (in this case a mock of the DOM object) to be passed in instead of hard coded in your logic (alg)

Categories