0

So, basically, a there is some poor code that I cannot change that needs to be tested. Traditionally, you inject your mocked dependencies, but with this code, I cannot do so, because there are no setter methods. Worse, the function I need to test calls a bunch of static factory methods-I can't just use the MockUp strategy to swap out the implementation there, because there is no class instance to be injected at all.

In C/++, you can retrieve a pointer to a function and know it's type by it's signature. If you changed the pointer, then you could potentially change how the stack was constructed by the compiler and you could pass function's around and all that Jazz.

Is there a way to use the Deencapsulation API to replace a static method implementation? Using this, I could write my own class, descend from the traditional, but return mocked objects in order that dependency injection still be achieved?

public class TestedClass {
    public static void testedMethod() {
        UnMockableType instanceVariable = 
           UnInjectableFactory.staticFactoryConstructor();
        instanceVariable.preventControlFlowInfluenceThroughMocking();
    }
}
Adam Miller
  • 1,756
  • 1
  • 25
  • 44
  • The `Deencapsulation` class is just a bunch of Reflection-based utility methods; to "replace a static method implementation" you would use the mocking APIs (either `@Mocked` or a `MockUp`). The question is not very clear, but mocking a static method should be no problem. – Rogério Mar 02 '15 at 20:43
  • Well, if you can't inject the mocked method in order to return a mocked instance from the static factory method, then how does making a MockUp based method mock even help? – Adam Miller Mar 02 '15 at 20:44
  • I probably did not fully understand the question; could you provide some example code showing what it is that you are trying to achieve? In any case, the JMockit APIs provide all kinds of facilities for mocking and dependency injection, so it should be doable. – Rogério Mar 02 '15 at 20:46
  • I added an example, I think the example is accurate, but I'm going off memory here, since I don't have the code with me at the moment. – Adam Miller Mar 02 '15 at 20:49

1 Answers1

1

Easy enough:

@Test
public void exampleTestUsingAMockUp()
{
    new MockUp<UnMockableType>() {
        @Mock
        void preventControlFlowInfluenceThroughMocking() {}
    };

    TestedClass.testedMethod();
}

Above, UnInjectableFactory isn't mocked because it doesn't need to be (assuming it simply instantiates/recovers an UnMockableType).

It could also be done with @Mocked and the Expectations API.

Rogério
  • 16,171
  • 2
  • 50
  • 63
  • The problem with this is, the instance that the static factory returns is *not* the mocked instance; yes you can declare it mocked and you can declare it injected. But those instances are just local to the test class that contains the test definitions. The new MockUp creates a an alternative type, but that type's definition of preventControlFlowInfluenceThroughMocking is not what gets executed, it should still be the original. – Adam Miller Mar 02 '15 at 20:58
  • Assuming that `UnMockableType` is a class, then applying a `MockUp` will affect *all* of its instances, present and future (for the duration of the test). If it is a base type (an interface or a base class), then it would be better to use `@Capturing`. – Rogério Mar 02 '15 at 21:01
  • Ok, I'll wait and just test this answer when I get a chance. I take your word for it, because what I'm used to is JMock, not JMockIt, which has different semantics for how dependency injection is performed. – Adam Miller Mar 02 '15 at 21:02
  • Actually, JMockit does everything jMock does in pretty much the same way; it does contain a lot more features than jMock, though, including advanced support for dependency injection through the `@Tested` and `@Injectable` annotations. – Rogério Mar 02 '15 at 21:04
  • The main difference here is the lack of a need for a setter method to replace the factory class or instance variable, whereever you decided to place the dependency actually injected anyway. – Adam Miller Mar 02 '15 at 21:06
  • Yes, in JMockit's case you don't need to have a way of passing mocked instances to the code under test. If said code does rely on dependency injection, though, you can use those two last annotations I mentioned for automatic injection. – Rogério Mar 02 '15 at 21:08
  • Yeah, dependency injection does still seem to be the way to go since spring does so much with it. JMockIt goes above what should be required from reasonable code. But if you have abomination code (like what I am forced to deal with), then you need to get at it, and for that I appreciate what JMockIt does. Thanks, I appreciate it a lot. – Adam Miller Mar 02 '15 at 21:12
  • Well, I would say you need JMockit if you want to unit test proper object-oriented code. For example, if you follow the well-known advice of "design for inheritance or prohibit it", you'll have plenty of `final` classes which cannot be mocked otherwise. Also, DI frameworks like Spring and CDI usually force the creation of stateless "Transaction Scripts", which are non-objects and typically display low cohesion; with JMockit I can create high-cohesion *objects* and still have them easily unit tested. – Rogério Mar 03 '15 at 15:10