An Automatic Refactoring Framework for Replacing

Test-Production Inheritance by Mocking Mechanism

Mock Syntax Variations

In Section 5.1 Auto-Refactoring Procedure, we mentioned that there are several syntax variations for the mocking instance creations and method stubbings. We summarized the variations and the corresponding use scenarios here.

Spy Concrete Class

As shown in Figure 2, we use spy to create mocking object when productionClass is a concrete class. Spy creates a real object and all methods defined in productionClass still behave in the same way as the normal instance.

Figure 2: Spy Concrete Class

Mock Interface

As shown in Figure 1, we use mock to create mocking object when productionClass is an interface without any default methods. The mocking object is merely a skeleton and the method remains unimplemented, that is, methods with return will return the default value (e.g., 0 for int, false for boolean, null for Object) and void methods will simply do nothing.

Figure 1: Mock Interface

Spy Real Instance

As shown in Figure 3, we create spy on a real instance when testSubclass invoked the non-default super constructor (line 2). This syntax ensure that the behavior of testSubclass and mocking object are consistent.

Spy Abstract Class

As shown in Figure 4, we use mock and withSettings() to create mocking object when productionClass is abstract and testSubclass invoked the non-default super constructor (line 2). We invoked the super constructor by calling useConstrucotr() method (line 14) when creating the mocking object. Since we use defaultAnswer(CALLS_REAL_METHODS), we actually create a mocking object that retain the original behavior with productionClass.

Figure 4: Spy Abstract Class

doAnswer

doAnswer entriely replaces the original method behavior, working similar to method overridden in inheritance. doAnswer were used on spying object to preserve the "overridden" behavior.

Figure 5: doAnswer Syntax

thenAnswer

thenAnswer adds additional actions to the stubbed method. It ensures tyep safe and more readable thus should be preferred whenever possible. We choose to use thenAnswer syntax when mocking production interfaces.

Figure 6: thenAnswer Syntax

doReturn

doReturn works similar with doAnswer which replaces the original method behavior. doReturn is used when the overridden method only contain a single return statement. We use doReturn when spying real objects since calling real methods on a spy object may bring side effects.

Figure 7: doReturn Syntax

thenReturn

thenReturn is used to stub method on mocking object when the overridden method only contain a single return statement.

Figure 8: thenReturn Syntax

doThrow

doThrow is used to stub method on spying object when the overridden method only contain a single throw statement.

Figure 9: doThrow Syntax

thenThrow

thenThrow is used to stub method on mocking object when the overridden method only contain a single throw statement.

Figure 10: thenThrow Syntax

doNothing

doNothing is used for setting stub methods to do nothing. It only used for spying object since methods on mocking object do nothing by default.

Figure 11: doNothing Syntax

Pseudo-Code: translateToMocking

In section 5.1.3, we use translateToMocking to preserve the references on the mock object. The reference to the testSubClass attribute/method is replaced to be the reference to the extracted attribute/variables or methods in testClass'. Figure 8 shows the pseudo-code of the translateToMocking, which processes each statement from codeBody in a while loop:

For the current statement, curStmt, the algorithm first checks whether it has reference to an attribute, TSC.attr, of testSubClass. If so, the reference to TSC.attr needs to be replaced properly (from line 2 to line 13). There are two different ways to replace the reference to TSC.attr, depending on its usage type introduced earlier. If TSC.attr is a checker/counter (line 3), and the curStmt is an assertion statement, we replace this assertion by MockVerify (line 4). If curStmt is not an assertion statement, it actually indicates an error, since checker/counter can only be referenced in an assertion statement by its definition (line 5). Otherwise, TSC.attr is a general attribute type (line 7), we just replace the reference to TSC.attr in curStmt by the reference to the local variable in the testCase (line 8) or the attribute in the testClass (line 10), depending on where the TSC.attr is extracted to be.

Figure 12. tanslateToMocking

Eclipse Plugin Link

As mentioned in Section 5.2 Implementation, we implemented the auto-refactoring framework as an Eclipse plugin. You can download the folder through this link: JMocker. You can install the plugin manually from local by providing it the folder.

Paper DataSets

Manual Refactoring Datasets

A detailed manual refactoring datasets for Table 1 in Section 3 Empirical Study. This table shows the distribution of classes filtered out by each filter.

Manual Refactoring Datasets

Auto-Refactoring Evaluation Datasets

A detailed auto-refactoring datasets for Table 3 in Section 6 Evaluation. This table shows the distribution of classes filtered out by each filter.

Auto-Refactoring Evaluation Datasets

Qualitative Evaluation

The raw survey data for Qualitative Evaluation in Section 6 Evaluation.

Qualitative Evaluation