2016-11-17 4 views
0

скажем, у меня есть класс со следующим конструктором:Как издеваются набор свойств в конструкторе

public class MyImpl extends Abstract<Foo> { 

    @Autowired 
    private FooClass foo; 

    private final ThreadPoolExecutor executor; 

    public MyImpl(String name, int num) { 
     super(name); 
     this.executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(num); 

    } 

Где-то этот класс имеет следующий метод:

@Override 
    public void doThis() { 
     for (int i = 0; i < num; i++) { 
      executor.execute(() -> foo.doMethod()); 
     } 
     executor.shutdown(); 

     super.doThis(); 
    } 

Теперь я хочу, чтобы проверить, что foo.doMethod был вызван 4 раза и, что executor.execute(any()) и executor.shutdown() также назывались 4 раза.

До сих пор я

@RunWith(PowerMockRunner.class) 
@PrepareForTest(Executors.class) 
public class MyImplTest { 

    private static final int NUM = 4; 

    @Mock 
    private FooClass foo; 
    @Mock 
    private ThreadPoolExecutor executor; 
    @InjectMocks 
    private MyImpl imyImpl = new MyImpl("Name", NUM); 

    @Test 
    public void shouldCallFourTimes() throws Exception { 
     PowerMockito.mockStatic(Executors.class); 
     when(Executors.newFixedThreadPool(NUM)).thenReturn(foo); 

     myImpl.doThis(); 

     PowerMockito.verifyStatic(); 
     Executors.newFixedThreadPool(NUM); 
     verify(foo, times(NUM)).doMethod()); 

    } 

Однако это не работает. Моккито говорит, что никакого взаимодействия с моими издевательскими Исполнителями не было. Поскольку @Autowired зависимости не являются частью конструктора, мне нужно указать конструктор в поле с @InjectMocks. Однако, к моменту I PowerMockito.mockStatic(Executors.class), конструктор MyImpl уже создал своего собственного исполнителя через «реальный» Executors.newFixedThreadPool.

Любая идея, как я могу это решить?

UPDATE: Видимо это не большое дело, чтобы изменить дизайн и теперь у меня есть следующие:

public class MyImpl extends Abstract<Foo> { 

    @Autowired 
    private FooClass foo; 

    private final ThreadPoolExecutor executor; 

    public MyImpl(String name, ThreadPoolExecutor executor) { 
     super(name); 
     this.executor = executor; 
} 

тест:

@Mock 
private ThreadPoolExecutor executor; 
@InjectMocks 
private MyImpl imyImpl = new MyImpl("Name", executor); 

Однако executor как-то нуль при прибытии в конструктор.

+0

вы не должны создавать новый объект с «новым MyImpl («Имя», NUM), @InjectMocks автоматически создает экземпляр – kuhajeyan

+0

Если я этого не сделаю, Mockito будет жаловаться, что MyImpl не имеет конструктора по умолчанию. Обратите внимание, что 'FooClass foo' не передается в качестве параметра конструктору – user3083022

+0

какое-то объяснение относительно того, как было бы очень полезно – user3083022

ответ

4

Проблема заключается в дизайне MyImpl.

Вместо того, чтобы создавать исполнитель пула потоков в конструкторе, он должен быть передан ему. Вы можете поместить статический заводский метод для своего текущего конструктора на место, чтобы у вас все еще была возможность создать экземпляр с теми же аргументами, которые вы используете сейчас.

Зачем вам нужно отличить ThreadPoolExecutor? Это позволяет вам зависеть от конкретной реализации. Если вам это не нужно, вам лучше с java.util.concurrent.ExecutorService.

Тогда у вас есть все на месте, чтобы использовать простой mockito с обычным ExecutorService макет.

+0

Да, я начинаю думать, что это единственный способ. – user3083022

+0

Теперь я столкнулся с другими проблемами ... Я обновил вопрос – user3083022

+1

@ user3083022 Не используйте в этом случае '@ InjectMocks'. Создайте экземпляр непосредственно в тестовом примере. В то время, когда конструктор называется Mockito, у него не было возможности оценить аннотацию '@ Mock'. – SpaceTrucker

0

Я думаю, проблема была бы ваши имитировали классы не получают инъекции,

вы можете попробовать что-то вроде этого,

@Mock 
private FooClass foo; 
@Mock 
private ThreadPoolExecutor executor; 

private MyImpl imyImpl; 

@Before 
public void setUp() throws Exception { 
    imyImpl = new MyImpl("Name", NUM); 
    impl.setFoo(foo); 
    impl.setExecutor(executor); 
} 

// Тест

+0

Я не хочу позволять устанавливать исполнителя извне – user3083022

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