2016-09-21 1 views
0

Мне нужно написать тест PartitionMapperTest для моего класса Java PartitionMapper. Этот класс имеет частные поля с аннотациями @Inject, но у него есть только конструктор no-param.Ввод частных полей с @Inject во время теста?

Для теста я хочу создать partitionMapper перед любым тестом и ввести значения в его частные поля. Затем тестер проверяет метод mapper mapPartitions и утверждает значения. Однако я не знаю, как вводить эти значения в partitionMapper.

PartitionMapper.java

@Named 
public class PartitionMapper implements javax.batch.api.partition.PartitionMapper { 

    @Inject 
    private JobContext jobContext; 

    @Inject 
    @BatchProperty 
    private String fetchSize; 

    @Inject 
    @BatchProperty 
    private String rowsPerPartition; 

    // other batch properties ... 

    @PersistenceUnit(unitName = "h2") 
    private EntityManagerFactory emf; 

    @Override 
    public PartitionPlan mapPartitions() throws Exception { 
     // ... 
    } 
} 

PartitionMapperTest.java

public class PartitionMapperTest { 

    private PartitionMapper partitionMapper; 

    @Before 
    public void setUp() { 
     // Prepare JobContext, batch properties to inject ... 

     // Instantiation 
     partitionMapper = new PartitionMapper(); 

     // TODO How to inject these objects into partitionMapper? 
    } 

    @Test 
    public void testMapPartitions() throws Exception { 
     PartitionPlan partitionPlan = partitionMapper.mapPartitions(); 
     for (Properties p : partitionPlan.getPartitionProperties()) { 
      // Assertions here ... 
     } 
    } 

    // ... 
} 

Я на самом деле осуществить реальную PartitionMapperTest основанную на Mockito и PowerMock, который можно увидеть на моем GitHub. Проблема в том, что существует так много предположений, что это приводит к очень плохому коду для понимания пользователями. Я ищу другое решение для его рефакторинга.

ответ

2

Есть ли причина иметь конструктор без аргументов?

Я бы рекомендовал вам использовать инъекцию конструктора вместо инъекции в поле. Это решит вашу проблему.

Например, вместо:

public class Foo { 
    @Inject 
    private Bar bar; 
} 

сделать это:

public class Foo { 
    private Bar bar; 

    public Foo(@Inject Bar bar) { 
     this.bar = bar; 
    } 
} 

Если вы определяете точки впрыска таким образом, у вас есть чистый API и ваш класс может быть использован в не КДИТЕ среды (например, модульные тесты).

Существует много ресурсов, связанных с «инъекцией впрыска VS-инжектора конструктора» ... Также в режиме stackoverflow, например. https://stackoverflow.com/a/19382081/4864870.

+0

Вы Ответом является хорошей идеей. Вероятно, я его выберу. Однако мне интересно узнать, как CDI вводит значения в частные поля? Я имею в виду, что нет сеттеров, как они это достигают? Если я применил тот же механизм, могу ли я добиться тоже? (Внедрить их самостоятельно) –

+0

Я хочу иметь только конструктор без аргументов, потому что я не хочу, чтобы кто-нибудь создавал этот внутренний класс в API. Но они все равно могут сделать это на самом деле:/ –

+1

Полевые инжекционные пути требуют отражения, насколько я знаю. Я предполагаю, что это делается следующим образом: 'Поле поля = Example.class.getDeclaredField (" fieldName "); field.setAccessible (истина); field.set (instance, value); '. Если вы хотите заставить свой класс использовать только внутренне, вы можете сделать свой пакет конструктора приватным. Это не 100% -ное решение, но лучше, чем ничего. Если вы это сделаете, убедитесь, что ваш тест находится в одном пакете ...;) –

0

Используйте защищенные поля вместо частного, чтобы иметь возможность издеваться поля в тестовом модуле:

@Named 
public class PartitionMapper implements javax.batch.api.partition.PartitionMapper { 

    @Inject 
    JobContext jobContext; 

    @Inject 
    @BatchProperty 
    String fetchSize; 

    @Inject 
    @BatchProperty 
    String rowsPerPartition; 

    // other batch properties ... 

    @PersistenceUnit(unitName = "h2") 
    EntityManagerFactory emf; 

    @Override 
    public PartitionPlan mapPartitions() throws Exception { 
     // ... 
    } 
} 
+0

На самом деле я могу издеваться над ними в приватном поле, используя mockito и powerermock. И я не хочу менять свой исходный код, чтобы адаптировать мой тест. И я думаю, вы неправильно поняли мой вопрос. Я делал слишком много макетов ранее, поэтому теперь я хочу переключиться на инъекционный подход без насмешек. Любая идея о том, как ее достичь? –

Смежные вопросы