Psa Mock

0 views
Skip to first unread message

Lirim Collard

unread,
Aug 4, 2024, 4:51:28 PM8/4/24
to tazudetmai
Mockfunctions allow you to test the links between code by erasing the actual implementation of a function, capturing calls to the function (and the parameters passed in those calls), capturing instances of constructor functions when instantiated with new, and allowing test-time configuration of return values.

All mock functions have this special .mock property, which is where data about how the function has been called and what the function returned is kept. The .mock property also tracks the value of this for each call, so it is possible to inspect this as well:


Mock functions are also very effective in code that uses a functional continuation-passing style. Code written in this style helps avoid the need for complicated stubs that recreate the behavior of the real component they're standing in for, in favor of injecting values directly into the test right before they're used.


Most real-world examples actually involve getting ahold of a mock function on a dependent component and configuring that, but the technique is the same. In these cases, try to avoid the temptation to implement logic inside of any function that's not directly being tested.


Once we mock the module we can provide a mockResolvedValue for .get that returns the data we want our test to assert against. In effect, we are saying that we want axios.get('/users.json') to return a fake response.


Still, there are cases where it's useful to go beyond the ability to specify return values and full-on replace the implementation of a mock function. This can be done with jest.fn or the mockImplementationOnce method on mock functions.


For cases where we have methods that are typically chained (and thus always need to return this), we have a sugary API to simplify this in the form of a .mockReturnThis() function that also sits on all mocks:


You can optionally provide a name for your mock functions, which will be displayed instead of 'jest.fn()' in the test error output. Use .mockName() if you want to be able to quickly identify the mock function reporting an error in your test output.


In computer science, a mock object is an object that imitates a production object in limited ways. A programmer might use a mock object as a test double for software testing. A mock object can also be used in generic programming.


In a unit test, mock objects can simulate the behavior of complex, real objects and are therefore useful when a real object is impractical or impossible to incorporate into a unit test. If an object has any of the following characteristics, it may be useful to use a mock object in its place:


For example, an alarm clock program which causes a bell to ring at a certain time might get the current time from a time service. To test this, the test must wait until the alarm time to know whether it has rung the bell correctly. If a mock time service is used in place of the real time service, it can be programmed to provide the bell-ringing time (or any other time) regardless of the real time, so that the alarm clock program can be tested in isolation.


Mock objects have the same interface as the real objects they mimic, allowing a client object to remain unaware of whether it is using a real object or a mock object. Many available mock object frameworks allow the programmer to specify which methods will be invoked on a mock object, in what order, what parameters will be passed to them, and what values will be returned. Thus, the behavior of a complex object such as a network socket can be mimicked by a mock object, allowing the programmer to discover whether the object being tested responds appropriately to the wide variety of states such mock objects may be in.


The definitions of mock, fake, and stub are not consistent across the literature.[1][2][3][4][5][6] None-the-less, all represent a production object in a testing environment by exposing the same interface.


Such a test object might contain assertions to examine the context of each call. For example, a mock object might assert the order in which its methods are called, or assert consistency of data across method calls.


In the book The Art of Unit Testing[7] mocks are described as a fake object that helps decide whether a test failed or passed by verifying whether an interaction with an object occurred. Everything else is defined as a stub. In that book, fakes are anything that is not real, which, based on their usage, can be either stubs or mocks.


Consider an example where an authorization subsystem has been mocked. The mock object implements an isUserAllowed(task : Task) : boolean[8] method to match that in the real authorization class. Many advantages follow if it also exposes an isAllowed : boolean property, which is not present in the real class. This allows test code to easily set the expectation that a user will, or will not, be granted permission in the next call and therefore to readily test the behavior of the rest of the system in either case.


Similarly, mock-only settings could ensure that subsequent calls to the sub-system will cause it to throw an exception, hang without responding, or return null etc. Thus, it is possible to develop and test client behaviors for realistic fault conditions in back-end sub-systems, as well as for their expected responses. Without such a simple and flexible mock system, testing each of these situations may be too laborious for them to be given proper consideration.


A mock database object's save(person : Person) method may not contain much (if any) implementation code. It might check the existence and perhaps the validity of the Person object passed in for saving (see fake vs. mock discussion above), but beyond that there might be no other implementation.


Apart from complexity issues and the benefits gained from this separation of concerns, there are practical speed issues involved. Developing a realistic piece of software using TDD may easily involve several hundred unit tests. If many of these induce communication with databases, web services and other out-of-process or networked systems, then the suite of unit tests will quickly become too slow to be run regularly. This in turn leads to bad habits and a reluctance by the developer to maintain the basic tenets of TDD.


The use of mock objects can closely couple the unit tests to the implementation of the code that is being tested. For example, many mock object frameworks allow the developer to check the order of and number of times that mock object methods were invoked by the real object being tested; subsequent refactoring of the code that is being tested could therefore cause the test to fail even though all mocked object methods still obey the contract of the previous implementation. This illustrates that unit tests should test a method's external behavior rather than its internal implementation. Over-use of mock objects as part of a suite of unit tests can result in a dramatic increase in the amount of maintenance that needs to be performed on the tests themselves during system evolution as refactoring takes place. The improper maintenance of such tests during evolution could allow bugs to be missed that would otherwise be caught by unit tests that use instances of real classes. Conversely, simply mocking one method might require far less configuration than setting up an entire real class and therefore reduce maintenance needs.


Mock objects have to accurately model the behavior of the object they are mocking, which can be difficult to achieve if the object being mocked comes from another developer or project or if it has not even been written yet. If the behavior is not modelled correctly, then the unit tests may register a pass even though a failure would occur at run time under the same conditions that the unit test is exercising, thus rendering the unit test inaccurate.[10]


unittest.mock provides a core Mock class removing the need tocreate a host of stubs throughout your test suite. After performing anaction, you can make assertions about which methods / attributes were usedand arguments they were called with. You can also specify return values andset needed attributes in the normal way.


Additionally, mock provides a patch() decorator that handles patchingmodule and class level attributes within the scope of a test, along withsentinel for creating unique objects. See the quick guide forsome examples of how to use Mock, MagicMock andpatch().


Mock and MagicMock objects create all attributes andmethods as you access them and store details of how they have been used. Youcan configure them, to specify return values or limit what attributes areavailable, and then make assertions about how they have been used:


The patch() decorator / context manager makes it easy to mock classes orobjects in a module under test. The object you specify will be replaced with amock (or other object) during the test and restored when the test ends:


When you nest patch decorators the mocks are passed in to the decoratedfunction in the same order they applied (the normal Python order thatdecorators are applied). This means from the bottom up, so in the exampleabove the mock for module.ClassName1 is passed in first.


Mock allows you to assign functions (or other Mock instances) to magic methodsand they will be called appropriately. The MagicMock class is just a Mockvariant that has all of the magic methods pre-created for you (well, all theuseful ones anyway).


For ensuring that the mock objects in your tests have the same api as theobjects they are replacing, you can use auto-speccing.Auto-speccing can be done through the autospec argument to patch, or thecreate_autospec() function. Auto-speccing creates mock objects thathave the same attributes and methods as the objects they are replacing, andany functions and methods (including constructors) have the same callsignature as the real object.


Mock is a flexible mock object intended to replace the use of stubs andtest doubles throughout your code. Mocks are callable and create attributes asnew mocks when you access them [1]. Accessing the same attribute will alwaysreturn the same mock. Mocks record how you use them, allowing you to makeassertions about what your code has done to them.

3a8082e126
Reply all
Reply to author
Forward
0 new messages