Mockito - Как избежать вставки данных в БД? - PullRequest
0 голосов
/ 27 августа 2018

Как мы можем написать mockito для приведенного ниже кода?Это было написано в обычном JDBC.Мне нужно создать макет всего этого кода, используя метод main (который управляет всей логикой обновления данных).

Мне действительно нужна помощь в том, чтобы избегать вставки фактических данных.Может ли кто-нибудь, пожалуйста, наставить меня?

public class PaytPaytmBilling { 
    private static Category logger = Category.getInstance(PaytPaytmBilling.class);
    private static InputStream inputS = XY.class.getResourceAsStream("/paytm.properties");

    private static final INSERT_QUERY = "INSERT STATEMENT";


    private static void insertPaytPaytmBilling(ArrayList allPaytPaytmBill) throws Exception{

        conn = getConnection(userId, passwd, prop.getProperty("databaseURL"));

        String childSql = buildInsertPaytPaytmBillSql();

        PreparedStatement pStatement =  conn.prepareStatement(childSql);

        for (int i=0; i<allPaytPaytmBill.size(); i++){
            PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);

            pStatement.setString(1, PaytmBill.getXX());
            pStatement.setString(2, PaytmBill.getYY());
            pStatement.setString(3, PaytmBill.getAA());
            pStatement.setLong(4, PaytmBill.getBB());
            pStatement.setLong(5, PaytmBill.getCC));            
            pStatement.setString(6, PaytmBill.getDD());
            pStatement.setInt(7, PaytmBill.getEE());
            pStatement.setInt(8, PaytmBill.getFF());
            pStatement.setString(9, "");
            pStatement.setString(10, "");
            pStatement.execute();       
        }   
        pStatement.close();
        conn.close();
    }

    private static void getDbConn() throws Exception {
        // Here get DB connection
    }


    public static void main(String[] args) throws Exception
    {
        ArrayList allPaytPaytmBill = new ArrayList();
        XY.init();
        getDbConn();
        // This query reads data from other tables and creates the data..
        String qmrString = qmr.buildQmrSql();

        allPaytPaytmBill = qmr.getAllMemberData(qmrString);

        insertPaytPaytmBilling(allPaytPaytmBill);
    }   
}

Тестовый класс Mockito:

@RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {
    private static Category logger = Category.getInstance(PaytmBillingTest.class);

    @Mock
    private DataSource ds;

    @Mock
    private Connection c;

    @Mock
    private PreparedStatement stmt;

    @Mock
    private ResultSet rs;

    private ArrayList<PaytmBill> allPaytmBill;

    @Before
    public void before() {
        allPaytmBill = new ArrayList<>();
        PaytmBill PaytmBill = new PaytmBill();
        PaytmBill.setAA("1182"); 
        PaytmBill.setBB("5122");
        PaytmBill.setCC("201807");
        PaytmBill.setDD(0L);
        PaytmBill.setEE(100);
        PaytmBill.setFF(0);
        PaytmBill.setGG(0);
        PaytmBill.setHH("A");
        PaytmBill.setII(null);
        PaytmBill.setJJ(null);

        allPaytmBill.add(PaytmBill);
    }

    @Test
    public void testPaytmBilling() {    
        PaytmBilling PaytmBilling = new PaytmBilling();

    }
}

1 Ответ

0 голосов
/ 27 августа 2018

Прежде всего, похоже, что вы не показываете использование реального кода.Например, вы добавили private static void getDbConn(), но код вызывает conn = getConnection(...), переменная conn нигде не объявлена ​​и т. Д. Это затрудняет реальную помощь в решении вашей проблемы.

Глядя на свой модульный тест,вы хотите смоделировать экземпляры определенных классов, используемых PaytPaytmBilling, таких как DataSource, Connection и PreparedStatement.Они называются «зависимостями».

Для этого вам нужно изменить PaytPaytmBilling, чтобы эти зависимости были «введены» (см. Внедрение зависимости ).Это означает, что они предоставляются PaytPaytmBilling через конструктор или установщик (или с некоторыми платформами, просто добавляя аннотацию к полю).

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

Чтобы написать хорошие модульные тесты, вынеобходимо написать (или реорганизовать) код для тестирования, что означает, что зависимости вводятся, а не получаются внутри класса.Также избегайте статических методов и данных (с константами все в порядке), они плохо работают с внедрением зависимостей и тестируемым кодом.

Так, например, DataSource может быть внедрен через конструктор, например так:

public class PaytPaytmBilling { 

    private static final String CHILD_SQL = "SELECT bladiebla...";

    private DataSource dataSource;        

    public PaytPaytmBilling(DataSource dataSource) {
        this.dataSource = dataSource;
    }

    public void insertPaytPaytmBilling(List<PaytmBill> allPaytPaytmBill) {
        // keeping the example simple here.
        // don't use String literals for the parameters below but read 
        // them from Properties (which you can mock for the unit test)
        Connection conn = dataSource.getConnection("userId", "passwd", "url");
        PreparedStatement pStatement = conn.prepareStatement(CHILD_SQL);
        for (int i=0; i<allPaytPaytmBill.size(); i++){
            PaytPaytmBill PaytmBill = (PaytPaytmBill) allPaytPaytmBill.get(i);
            pStatement.setString(1, PaytmBill.getXX());
            pStatement.setString(2, PaytmBill.getYY());
            pStatement.setString(3, PaytmBill.getAA());
            // ...
            pStatement.execute();       
        }               
        pStatement.close();
        conn.close();
    }

Если вы переписываете код, как описано выше, вы можете протестировать его следующим образом:

@RunWith(MockitoJUnitRunner.class)
public class PaytmBillingTest {

    // this will cause Mockito to automatically create an instance 
    // and inject any mocks needed
    @InjectMocks
    private PaytmBilling instanceUnderTest;

    @Mock
    private DataSource dataSource;

    // connection is not directly injected. It is obtained by calling 
    // the injected dataSource
    @Mock
    private Connection connection;

    // preparedStatement is not directly injected. It is obtained by
    // calling the connection, which was obtained by calling the 
    // injected dataSource
    @Mock
    private PreparedStatement preparedStatement;

    private List<PaytmBill> allPaytmBill;

    @Before
    public void before() {
        allPaytmBill = new ArrayList<>();
        PaytmBill paytmBill = new PaytmBill();
        paytmBill.setAA("1182"); 
        paytmBill.setBB("5122");
        paytmBill.setCC("201807");
        paytmBill.setDD(0L);
        paytmBill.setEE(100);
        paytmBill.setFF(0);
        paytmBill.setGG(0);
        paytmBill.setHH("A");
        paytmBill.setII(null);
        paytmBill.setJJ(null);

        allPaytmBill.add(PaytmBill);
    }

    @Test
    public void testPaytmBilling() {    
        // given
        when(dataSource.getConnection(anyString(), anyString(), anyString())).thenReturn(connection);
        when(connection.prepareStatement(anyString())).thenReturn(preparedStatement);

        // when
        instanceUnderTest.insertPaytPaytmBilling(allPaytPaytmBill);

       // then
       verify(pStatement).setString(1, paytmBill.getXX());
       verify(pStatement).setString(2, paytmBill.getYY());
       verify(pStatement).setString(3, paytmBill.getAA());
       // ...
       verify(pStatement).execute();
       verify(pStatement).close();
       verify(connection).close();
    }

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

Connection conn = dataSource.getConnection("userId", "passwd", "url");
PreparedStatement pStatement = conn.prepareStatement(childSql);
try {
    // processing steps
}
finally {
    pStatement.close();
    conn.close();
}

Или try-with-resources:

try (Connection conn = dataSource.getConnection("userId", "passwd", "url"),
     PreparedStatement pStatement = conn.prepareStatement(childSql)) {

    // processing steps
}

Поскольку Connection и PreparedStatement реализуют AutoCloseable интерфейс они будут закрыты автоматически, когда заканчивается блок try.Это возможно начиная с Java 7.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...