2015-08-05 2 views
4

У меня есть абстрактный класс BaseTemplate и несколько классов, расширяющих его. В одном конкретном классе (SmsTemplate extends BaseTemplate) у нас есть переменная Gson. У нас есть та же переменная (Gson) в абстрактном классе.Как ввести переменную в абстрактный класс при модульном тестировании подкласса?

В то время как единица измерения tesing конкретного класса, методы в абстрактном классе вызывается из конкретного класса. В моем модульном тесте я использую Whitebox.setInternalState(smsTemplateObj, gsonObj);, чтобы ввести объект Gson в частные члены SmsTemplate и BaseTemplate, но Gson вводится только в подкласс. В абстрактном классе его NULL, что означает не введенный. Ниже приведена реализация.

Может кто-нибудь рассказать, как ввести объект Gson в абстрактный класс?

abstract class BaseTemplate{ 

    private Gson gson;//Here its not getting injected 

    protected String getContent(Content content){ 
     return gson.toJson(content); // ERROR - gson here throws NPE as its not injected 
    } 
} 

class SmsTemplate extends BaseTemplate{ 

    private Gson gson;//Here its getting injected 

    public String processTemplate(Content content){ 
     String strContent = getContent(content); 
     ... 
     ... 
     gson.fromJson(strContent, Template.class); 
    } 
} 
+1

Сделать поле абстрактного класса защищаемого и удалить удалить поле из подкласса. – Stefan

+0

@Stefan - Ahh ... проблема в том, что объект Gson не используется во всех конкретных классах. – whoami

+0

Зачем вам нужна переменная gson в абстрактном классе И подкласс? – bryce

ответ

5

Whitebox.setInternalState() метод будет только установить значение первого поля он сталкивается с идущим вверх по иерархии объекта вы проходите. Поэтому, когда он найдет поле в вашем подклассе, он не будет выглядеть дальше и не изменит поле суперкласса.

Есть два решения для этого случая:

  • Изменить имена переменных. Если переменные имеют разные имена, вы можете просто вызвать Whitebox.setInternalState() дважды, по одному для каждой переменной.
  • Задайте поле вручную, используя отражение. Вы также можете просто установить поле без помощи Mockito, используя что-то вроде следующего фрагмента.

Отрывок:

Field field = smsTemplateObj.getClass().getSuperclass().getDeclaredField("gson"); 
field.setAccesible(true); 
field.set(smsTemplateObj, gsonObj); 
+0

большое спасибо, попробовал отражение, и это сработало ... – whoami

0

Вам нужен второй слой абстракции:

abstract class BaseTemplate{ 

    // private Gson gson;// no Gson here 

    protected String getContent(Content content){ 
     // do what you want without Gson 
    } 
} 

abstract class BaseTemplateWithGson extends BaseTemplate{ 

    protected Gson gson; 

    @Override 
    protected String getContent(Content content){ 
     return gson.toJson(content); 
    } 
} 

class SmsTemplate extends BaseTemplateWithGson { 

    public String processTemplate(Content content){ 
     String strContent = getContent(content); 
     ... 
     ... 
     gson.fromJson(strContent, Template.class); 
    } 
} 
+0

Мне нравится 2-й уровень абстракции. Есть ли другой подход к модульному тесту без второй абстракции? – whoami

+0

Для меня нет проблем с единичным тестированием, но с учетом ... Когда сложно что-то тестировать, попросите проблему с дизайном ;-) – bryce

+0

Не могли бы вы рассказать, что является проблемой дизайна при реализации? – whoami

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