how do you test requests to external services in tests? how to make mock ?
the common way is, to use a SandBoxâed Environment or a Virtual Machine like Oracle VirtualBox or Microsoftâs Virtual PC.
I do not quite understand. why do I need a virtual machine? How can I use it for a non-my external service? Iâm interested in how you make a mock
To test Software, that you donât trust, or if you take care about Viruses, Trojanâs or other Malware that could damage your existing System, I advise you to use a SandBox.
A SandBox is like a play ground Environment for a special Session - provide Operating System Facilities, but dont change or operate between the Software and Operating System directly.
For a SandBox, you donât need Install a second copy of Windows - it comes all inclusive.
But it is limited on some Resources.
A Virtual Machine is - like the Name says: virtual.
Here, you can make anything what you would do.
You can emulate Hardware for your Testâs - like virtual Hard Disk Drives - which comes as a
Image File (and you dont need a native Drive, to format the Drive with a Folder Structure.
Examples can be Microsoft NTFS, or FAT32 File System Formatâs)
Or, you can emulate Network Cardâs (NICâs), etc. âŚ
There are no known Limits - okay, sure: The Space (RAM, and DiskDrive, and Computer Speed) âŚ
Examples for Virtual Machines Providers are Microsoft VirtualPC, ORACLE Virtual Box, or VMWare.
On VMWare, take care:
- there you could use older Version of the Productâs, beecause new Versionâs consume a huge
amount of Ressourceâs
If you plan to virtualize a Operating System, to run paralell to your current Windows Session, make sure, you have VM-vt Features enabled in your PC-BIOS.
I can not give Support in this, because each Vendor use other Options, and Menu System - take a look to the Search Engine of your Trust.
But, back to the red line âŚ
VM-Box, and SandBoxâs are usefull things in Development Stage.
Because, if you damage the (virtual) System, you can quickly copy a Backup File, and start your
tries again with fresh Environment.
Thanks for reading
paule32
my question is not about that at all. You have a post request to an external service. You know which answer is correct and which is wrong, and you need to test your method, you cannot rely on an external service in tests, you need to somehow bypass the call to an external service in the test. For example this library for Erlang GitHub - eproxus/meck: A mocking library for Erlang
There is nothing out of the box. There are lots of options though. For example, implement a mock version of the library that calls the external service and load it instead of the real thing by changing the (library) search path. You can also use wrap_predicate/4 to create a wrapper around any predicate. That is intended to call the original, but of course you donât need to. You can even abolish/1 the old predicate and assert a new definition.
None of that is portable. Wrapping predicates is really SWI-Prolog specific. There is no portability in search path handling (but many systems have it) and ISO turned abolish/1
into something useless because you can only use it on dynamic code where, in addition to retractall/1
, it removes the predicate properties (dynamic, etc.) SWI-Prolog kept the pre-ISO semantics where abolish/1 applies to any predicate.
Than you need an alternative implementation for the external server. I donât know how much you can generalize that. I guess it can be anything.
I agreed - it can anything.
What you could use is a Proxy-Server, that can block by regex.
Else, I would use WireShark, to see, what goes over the line.
no, all this is not needed, you just need to replace the function for the duration of the test.
In simple words, in mock testing, we replace the dependent objects with mock objects. These mock objects simulate or âmockâ the behavior of real objects and exhibit the exact characteristics of the authentic ones. The main goal of mock testing is to centralize the focus on the testing without being concerned about the dependencies.
Letâs take an example- You have a web service that makes a POST request to
update or store new entries in the API server every time you hit submit on a form.
We do not need to store unnecessary test data in the server each time we run a
test. Mock testing allows the user to replace the service with a mock object to validate the functionality without storing redundant information.
wrap_predicate/4 can do that. After the test you simply use unwrap_predicate/2 to restore the old behavior. This is used by trace/1,2 as well as tabling.
So, you get something like this:
?- wrap_predicate(http_client:http_get(URL, Data, Options), test,
_Wrapped, mock_http_get(URL, Data, Options)).
<run tests>
?- unwrap_predicate(http_client:http_get/3, test).
I donât need all calls to mock , but now I got that everything has changed.
or it is possible to install and cancel for each test?
Isnât that what the unwrap_predicate/2 call does? It removes a named wrapper. If you want examples, look at the implementation of trace/2, which prints the passes through the âportsâ (call, exit, fail, redo).
thanks, I already figured it out.
Jan: if the test fails in the middle, will unwrap_predicate fail to run? It sounds more like a try/finally situation, and by then, the setup becomes tedious. Is there a way to override a predicate for the duration of the test with automatic unwrapping regardless of the testâs outcome?
See setup_call_cleanup/3, where you do the wrap in the setup, the test in the call and the unwrap in the cleanup phase of this predicate. This predicate
- calls the setup as once/1. On anything but success, we are done. I.e., if the setup fails, the call fails and if it throws throws. Once we get through the setup, it is ensured that the cleanup is called, even if a resource error or interrupt happens between the setup and call.
- call the call phase. Now, the cleanup is used as finalize step. Completion state (fail, succeed, throw) is that of the call phase, unless the cleanup throws a âmore urgentâ error. For example, if call raises some normal error and cleanup gets an abort, execution is still aborted.
Can it be done once for all the tests in a module, or in a way that it is not that intrusive?
Shouldnât the tests be hermetic automatically, with the test runner isolating their side effects from each other? Then we could just assert things in a test and not have to retract them with a setup_call_cleanup/3.
You can add setup(Goal) and cleanup(Goal) to the begin_tests/2 as well as each individual test. Also there we guarantee that the cleanup is called.
SWI-Prolog (or any Prolog I know) doesnât really provide fully side-effect-free isolation. We could consider running each test using snapshot/1
, which would deal with assert/retract. That might be a good idea. Alternatively we could run each test in a thread and use thread_local/1 rather than dynamic/1. That isolates a little more as also flags and global variables are thread specific. But, not everything runs completely unmodified in a thread (99% does). The safe solution would be to fork, but that is relatively slow and does not work on Windows.