Mock Trainwreck
   HOME

TheInfoList



OR:

In
computer science Computer science is the study of computation, information, and automation. Computer science spans Theoretical computer science, theoretical disciplines (such as algorithms, theory of computation, and information theory) to Applied science, ...
, the term Mock Trainwreck refers to the difficulty of mocking a deeply nested model structure. Mocking is the creation of mock objects which can be used to mimic the behavior of real objects, often because it is hard to test with the real objects. A trainwreck is multiple levels of method calls (called a chain), which each return objects upon which new methods can be called. Deeply nested models go against the
Law of Demeter The Law of Demeter (LoD) or principle of least knowledge is a design guideline for developing software, particularly object-oriented programs. In its general form, the LoD is a specific case of loose coupling. The guideline was proposed by Ian Hol ...
because the property's property must be accessed. The Law of Demeter, also known as the principle of least knowledge is a design guideline to promote loose
coupling A coupling is a device used to connect two shafts together at their ends for the purpose of transmitting power. The primary purpose of couplings is to join two pieces of rotating equipment while permitting some degree of misalignment or end mo ...
of data structures that are not closely related, and thus should probably not be coupled together. In addition, this level of coupling can be considered an inappropriate intimacy
code smell In computer programming, a code smell is any characteristic in the source code of a program that possibly indicates a deeper problem. Determining what is and is not a code smell is subjective, and varies by language, developer, and development met ...
. Mock trainwrecks should be avoided when possible. This is because not only does it makes it harder to test the code which uses them, but also because they are harder to work with from a design standpoint. In addition, it increases the amount of information an object can access, due to its close relation with other parameters that are not related to its main functionality.


Example of a trainwreck

If someone wanted to write a test looking for a library that receives public funding, or by its head librarian, he or she might use code like the following: Java assertEqual( l.getHeadLibrarian() .getName().split(" ") , "Smith") assertEqual( l.getFunding().getType() , "public") Ruby l.headLibrarian.name.split(/ +/).last.should

"Smith" l.funding.type.should

"public"
To mock up an object that matches the search result, they would have to have mocking code like what follows: Java HeadLibrarian h = mock(HeadLibrarian.class); when(h.getName()).thenReturn("Jane Smith"); Funding f = mock(Funding.class); when(f.getType()).thenReturn("public"); Library l = mock(Library.class); when(l.getHeadLibrarian()).thenReturn(h); when(l.getFunding()).thenReturn(f); Ruby h = mock('HeadLibrarian', :name => 'Jane Smith') f = mock('Funding', :type => 'public') l = mock('Library', :HeadLibrarian => h, :Funding => f) This is an example of a mock trainwreck, because it is a mock up of two unrelated objects, but it relies on a class, Library, to point to them both.


Ways to avoid the trainwreck

A mock trainwreck can be avoided by making general code changes or by more specific changes through the use of dependency injection and libraries. General code changes allow a nested model to be made more simple, primarily though the creation of an assessor to access the sub property. This prevents the deep nesting which causes the mock trainwreck, and this assessor can be mocked easily.


Dependency injection

Dependency injection In software engineering, dependency injection is a programming technique in which an object or function receives other objects or functions that it requires, as opposed to creating them internally. Dependency injection aims to separate the con ...
(DI), the process by which a dependency is passed to the client which will use it, can be used to soften the trainwreck. One method of DI that is easy to use is a location object to reduce the complexity of building the mock object. Below is the example above reworked with a DI build_mock method to help set mock values on dependent objects. While for this simple example it doesn't appear to help much, in a more complicated scenario it could reduce complexity in manually setting the values. def build_mock(name, map, locator, refs) obj = mock(name, map) refs.each do , ref, obj.send("#=", locator ef.to_sym end obj end locator = locator HeadLibrarian= mock('HeadLibrarian', :name => 'Jane Smith') locator
Funding Funding is the act of providing resources to finance a need, program, or project. While this is usually in the form of money, it can also take the form of effort or time from an organization or company. Generally, this word is used when a firm use ...
= mock('Funding', :type => 'public') locator
Library A library is a collection of Book, books, and possibly other Document, materials and Media (communication), media, that is accessible for use by its members and members of allied institutions. Libraries provide physical (hard copies) or electron ...
= build_mock('Library', , locator, HeadLibrarian', 'Funding'


Libraries


Mockito

Testing library in various languages can make the mock trainwreck easier to navigate with helpers. An example is Mockito that provides annotations to assist in injecting mocks into objects. Using the @InjectMocks annotation and @Mock annotation, when Mockito initializes all the mocks it will inject Library with the mocks for funding and head librarian. public class LibraryTester


Demeter

The use of libraries can also be used to address mock trainwreck. One such library is calle
demeter
and it can be used to provide Law of Demeter
duck typing In computer programming, duck typing is an application of the duck test—"If it walks like a duck and it quacks like a duck, then it must be a duck"—to determine whether an object can be used for a particular purpose. With nominative ...
assessors that automatically creates assessors for single level nested models. By using this library, a person can mock the assessors that their code uses of the child function, as seen in the example below. require "demeter" class Library extend Demeter demeter :HeadLibrarian demeter :Funding def initialize @HeadLibrarian = HeadLibrarian.new @Funding = Funding.new end end l = mock('Library', :HeadLibrarian_name => 'Jane Smith', :Funding.type => 'public') l.HeadLibrarian_name #Jane Smith


References

{{Reflist Unit testing