How to introduce ridicule when testing classes using CDI in production

I am programming in Java SE using WELD-SE for dependency injection. Therefore, class dependencies look something like this:

public class ProductionCodeClass { @Inject private DependencyClass dependency; } 

When writing a unit test for this class, I create a mock for DependencyClass , and since I donโ€™t want to run a full CDI environment for every run that I run, I โ€œenterโ€ the layout manually:

 import static TestSupport.setField; import static org.mockito.Mockito.*; public class ProductionCodeClassTest { @Before public void setUp() { mockedDependency = mock(DependencyClass.class); testedInstance = new ProductionCodeClass(); setField(testedInstance, "dependency", mockedDependency); } } 

The statically imported setField() method setField() I wrote myself in a class with the tools that I use when testing:

 public class TestSupport { public static void setField( final Object instance, final String field, final Object value) { try { for (Class classIterator = instance.getClass(); classIterator != null; classIterator = classIterator.getSuperclass()) { try { final Field declaredField = classIterator.getDeclaredField(field); declaredField.setAccessible(true); declaredField.set(instance, value); return; } catch (final NoSuchFieldException nsfe) { // ignored, we'll try the parent } } throw new NoSuchFieldException( String.format( "Field '%s' not found in %s", field, instance)); } catch (final RuntimeException re) { throw re; } catch (final Exception ex) { throw new RuntimeException(ex); } } } 

What I don't like about this solution is that I need this assistant over and over again in any new project. I already packaged it as a Maven project, which I can add as a test dependency to my projects.

But isnโ€™t there anything ready in some other shared library that I miss? Any comments on my way of doing this in general?

+6
source share
2 answers

Mockito supports this out of the box:

 public class ProductionCodeClassTest { @Mock private DependencyClass dependency; @InjectMocks private ProductionCodeClass testedInstance; @Before public void setUp() { testedInstance = new ProductionCodeClass(); MockitoAnnotations.initMocks(this); } } 

@InjectMocks annotation will introduce classes or interfaces that mocked the test class, in this case DependencyClass :

Mockito tries to type by type (using the name in case the types are the same). Mockito doesn't throw anything when the injection fails - you have to manually execute the dependencies.

Here I also use the @Mock annotation instead of calling mock() . You can use mock() anyway, but I prefer using annotations.

As a side note, there are reflection tools that support the functionality implemented in TestSupport . One such example is ReflectionTestUtils .

+7
source

Alternative when mockitos build function is not enough: Try needle4j.org

This is an injection / layout framework that allows you to embed mocks and specific instances, and also supports postConstruct for life cycle modeling.

  public class ProductionCodeClassTest { @Rule public final NeedleRule needle = new NeedleRule(); // will create productionCodeClass and inject mocks by default @ObjectUnderTest(postConstruct=true) private ProductionCodeClass testedInstance; // this will automatically be a mock @Inject private AServiceProductionCodeClassDependsOn serviceMock; // this will be injected into ObjectUnderTest @InjectIntoMany private ThisIsAnotherDependencyOfProdcutionCodeClass realObject = new ThisIsAnotherDependencyOfProdcutionCodeClass (); @Test public void test_stuff() { .... } } 
+1
source

All Articles