3

私はモックオブジェクトを使ったユニットテストの初心者です。EasyMockを使用しています。私はこの例を理解しようとしています:

import java.io.IOException;

public interface ExchangeRate {

    double getRate(String inputCurrency, String outputCurrency) throws IOException;

}

import java.io.IOException;


public class Currency {

    private String units;
    private long amount;
    private int cents;


    public Currency(double amount, String code) {
        this.units = code;
        setAmount(amount);
    }

    private void setAmount(double amount) {
        this.amount = new Double(amount).longValue();
        this.cents = (int) ((amount * 100.0) % 100);
    }

    public Currency toEuros(ExchangeRate converter) {
        if ("EUR".equals(units)) return this;
        else {
            double input = amount + cents/100.0;
            double rate;
            try {
                rate = converter.getRate(units, "EUR");
                double output = input * rate;
                return new Currency(output, "EUR");
            } catch (IOException ex) {
                return null;
            }
        }
    }

    public boolean equals(Object o) {
        if (o instanceof Currency) {
            Currency other = (Currency) o;
            return this.units.equals(other.units)
                    && this.amount == other.amount
                    && this.cents == other.cents;
        }
        return false;
    }

    public String toString() {
        return amount + "." + Math.abs(cents) + " " + units;
    }

}

import junit.framework.TestCase;
import org.easymock.EasyMock;
import java.io.IOException;

public class CurrencyTest extends TestCase {

    public void testToEuros() throws IOException {
        Currency testObject = new Currency(2.50, "USD");
        Currency expected = new Currency(3.75, "EUR");
        ExchangeRate mock = EasyMock.createMock(ExchangeRate.class);
        EasyMock.expect(mock.getRate("USD", "EUR")).andReturn(1.5);
        EasyMock.replay(mock);
        Currency actual = testObject.toEuros(mock);
        assertEquals(expected, actual);
    }

}

だから、私はどのように通貨がExchangeRateをtoEuros(..)メソッドで使用するのか疑問に思います。

rate = converter.getRate(units, "EUR");

はインターフェースであるgetRate(..)ため、メソッドの動作は指定されていません。ExchangeRate

/********************************************************************************/

だから私は自分で例をやってみます。以下は私のコードです:

/**
 *Interface to access data
 */
public interface Dao {
    public boolean getEntityById(int id) throws SQLException;
}

/**
 *Business class do something in business layer
 */
public class Bussiness {
    private Dao dao;

    public Dao getDao() {
        return dao;
    }

    public void setDao(Dao dao) {
        this.dao = dao;
    }

    public boolean doSomeThing(int id) throws SQLException {
        if(dao.getEntityById(id)) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) throws SQLException {
        Bussiness b = new Bussiness();
        b.doSomeThing(3);
    }
}


package tunl;

import java.sql.SQLException;

import org.easymock.EasyMock;
import org.testng.Assert;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;

    /**
     * This is my unit Test
     */
    @Test
    public class MyUnitTest {
        private Bussiness bussiness;
        private Dao mock;

        @BeforeTest
        public void setUp() {
            bussiness = new Bussiness();
            mock = EasyMock.createMock(Dao.class);// interface not class
            bussiness.setDao(mock);
        }

        public void testDoSomeThing() throws SQLException {
            EasyMock.expect(mock.getEntityById(3)).andReturn(true);
            EasyMock.replay(mock);
            Assert.assertTrue(bussiness.doSomeThing(3));
        }
    }

したがって、ユニットTessは正しく実行されます

しかし、ビジネスオブジェクトでmainメソッドを実行したい場合:

public static void main(String[] args) throws SQLException {
            Bussiness b = new Bussiness();
            b.doSomeThing(3);
}

Businessのコンストラクターを追加する必要があります。

public Bussiness() {
     dao = new DaoImpl();
}

したがって、私のビジネスクラスは次のとおりです。

package tunl;

import java.sql.SQLException;

public class Bussiness {
    private Dao dao;

    public Bussiness() {
        dao = new DaoImpl();
    }
    public Dao getDao() {
        return dao;
    }

    public void setDao(Dao dao) {
        this.dao = dao;
    }

    public boolean doSomeThing(int id) throws SQLException {
        if(dao.getEntityById(id)) {
            return true;
        } else {
            return false;
        }
    }

    public static void main(String[] args) throws SQLException {
        Bussiness b = new Bussiness();
        b.doSomeThing(3);
    }
}

また、Daoインターフェイスを実装する必要があります。

package tunl;

import java.sql.SQLException;

public class DaoImpl implements Dao {

    @Override
    public boolean getEntityById(int id) throws SQLException {
        if(id == 3) {
            System.out.println("System input 3 ");
            return true;
        }
        System.out.println("You have to input  3 ");
        return false;
    }

}

設計では、テストされるすべてのクラス(DaoImplなど)のインターフェイスを常に作成します。それで、それは正しいですか?

4

1 に答える 1

3

EasyMock は、インターフェイスに基づいてモック オブジェクトを作成します。モック オブジェクトは、インターフェイスのすべてのメソッドを実装し、指定したメソッド ( などexpect) については、呼び出されたときに指定された動作を「再生」します。

モック オブジェクトが作成されると、それは記録モードになります。この線

EasyMock.expect(mock.getRate("USD", "EUR")).andReturn(1.5);

が指定されたmock.getRateパラメータで呼び出された場合、 1.5 を返すことを指定します。次に、オブジェクトは呼び出しで再生モードになります

EasyMock.replay(mock);

これについてはすべて、ドキュメントで詳しく説明されています。

更新:あなたのコメントに -ここCurrencyのインスタンスが渡されExchangeRateます:

public Currency toEuros(ExchangeRate converter) { ... }

気にするのは、そのインターフェイスを実装するオブジェクトを取得することだけです。

rate = converter.getRate(units, "EUR");

呼び出すことができます。次に、テスト メソッドは、作成したモック オブジェクトを通貨オブジェクトに渡します。

Currency actual = testObject.toEuros(mock);

お役に立てれば; そうでない場合は、OOP、インターフェース、および継承に関する入門テキストを読んで理解を深めることができます。

回答のコード例では、DaoオブジェクトをBussiness内部で作成するのではなく、に渡す必要があります。これは、後者が単体テストを効果的に防止するためです。

public static void main(String[] args) throws SQLException {
        Bussiness b = new Bussiness();
        b.setDao(new DaoImpl());
        b.doSomeThing(3);
}

パラメーター化されたコンストラクターを追加Bussinessして、初期化を 2 つではなく 1 つのステップで行うこともできます。

于 2010-05-11T08:44:30.503 に答える