開発者ドキュメント

ユニットテスト – モッキングとは何ですか?なぜ?


mockito-logo、width = 400、height = 200

シンプルでは、​​実際のオブジェクトの動作を模倣するオブジェクトを作成しています。次のケーススタディを参照してください。

テスト済み:

  1. Java 1.8

  2. JUnit 4.12

  3. Mockito 2.0.73-beta

1. Javaの例

簡単な著者とブックの例。

1.1著者名で書籍のリストを返す

BookService

BookService.java

package com.mkyong.examples.mock;

import java.util.List;

public interface BookService {

    List<Book> findBookByAuthor(String author);

}

BookServiceImpl.java

package com.mkyong.examples.mock;

import java.util.List;

public class BookServiceImpl implements BookService {

    private BookDao bookDao;

    public BookDao getBookDao() {
        return bookDao;
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

    @Override
    public List<Book> findBookByAuthor(String name) {
        return bookDao.findBookByAuthor(name);
    }

}

BookDao.java

package com.mkyong.examples.mock;

import java.util.List;

public interface BookDao {

    List<Book> findBookByAuthor(String author);

}

BookDaoImpl.java

package com.mkyong.examples.mock;

import java.util.List;

public class BookDaoImpl implements BookDao {

    @Override
    public List<Book> findBookByAuthor(String name) {
       //init database
       //Connect to DB for data
       //return data
    }

}

1.2本のバリデーター。

BookValidatorService.java

package com.mkyong.examples.mock;

public interface BookValidatorService {

    boolean isValid(Book book);

}

FakeBookValidatorService.java

package com.mkyong.examples.mock;

public class FakeBookValidatorService implements BookValidatorService {

    @Override
    public boolean isValid(Book book) {
        if (book == null)
            return false;

        if ("bot".equals(book.getName())) {
            return false;
        } else {
            return true;
        }

    }
}

1.3

BookService

(` BookDao`に依存する)と

BookValidatorService`に依存する

AuthorServiceImpl`をレビューすると、単体テストを少し書くのが難しくなります。

AuthorService.java

package com.mkyong.examples.mock;

public interface AuthorService {

    int getTotalBooks(String author);

}

AuthorServiceImpl.java

package com.mkyong.examples.mock;

import java.util.List;
import java.util.stream.Collectors;

public class AuthorServiceImpl implements AuthorService {

    private BookService bookService;
    private BookValidatorService bookValidatorService;

    public BookValidatorService getBookValidatorService() {
        return bookValidatorService;
    }

    public void setBookValidatorService(BookValidatorService bookValidatorService) {
        this.bookValidatorService = bookValidatorService;
    }

    public BookService getBookService() {
        return bookService;
    }

    public void setBookService(BookService bookService) {
        this.bookService = bookService;
    }

   //How to test this method ???
    @Override
    public int getTotalBooks(String author) {

        List<Book> books = bookService.findBookByAuthor(author);

       //filters some bot writers
        List<Book> filtered = books.stream().filter(
                x -> bookValidatorService.isValid(x))
                .collect(Collectors.toList());

       //other business logic

        return filtered.size();


    }
}

ユニットテスト

`AuthorServiceImpl.getTotalBooks()`の単体テストを作成する

2.1 `AuthorServiceImpl`には2つの依存関係があります。両方が正しく設定されていることを確認する必要があります。

AuthorServiceTest.java

package com.mkyong.mock;

import com.mkyong.examples.mock.AuthorServiceImpl;
import com.mkyong.examples.mock.BookDaoImpl;
import com.mkyong.examples.mock.BookServiceImpl;
import com.mkyong.examples.mock.FakeBookValidatorService;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class AuthorServiceTest {

    @Test
    public void test__total__book__by__mock() {

       //1. Setup
        AuthorServiceImpl obj = new AuthorServiceImpl();
        BookServiceImpl bookService = new BookServiceImpl();
        bookService.setBookDao(new BookDaoImpl());//Where Dao connect to?
        obj.setBookService(bookService);
        obj.setBookValidatorService(new FakeBookValidatorService());

       //2. Test method
        int qty = obj.getTotalBooks("mkyong");

       //3. Verify result
        assertThat(qty, is(2));

    }

}

ユニットテストの上を渡すには、DAOレイヤーにデータベースを設定する必要があります。それ以外の場合、 `bookService`は何も返しません。

2.3上記のようなテストを行うにはいくつかの欠点があります。

  1. このユニットテストは遅いです. データベースを順番に起動する必要があるからです

DAOからデータを取得します。

  1. この単体テストは分離されておらず、常に外部に依存します

データベースのようなリソース。

  1. このユニットテストでは、テスト条件が常に同じであることを保証することはできませんが、

データベース内のデータは時間とともに変化する可能性があります。

  1. 単純なメソッドをテストするのはあまりにも多くの作業で、開発者はスキップします

テスト。

2.4

Solution

+解決策は明らかです。あなたは `BookServiceImpl`クラスの修正版を必要とします。これは常にテストのために同じデータを返します

模擬オブジェクト

  • モッキングとは何ですか?** 再び、モックとは、実際のオブジェクトの動作を模倣するオブジェクトを作成することです。

ユニットテスト – モックオブジェクト

3.1新しい「MockBookServiceImpl」クラスを作成し、常に著者「mkyong」の書籍と同じコレクションを返します。

MockBookServiceImpl.java

package com.mkyong.mock;

import com.mkyong.examples.mock.Book;
import com.mkyong.examples.mock.BookService;

import java.util.ArrayList;
import java.util.List;
//I am a mock object!
public class MockBookServiceImpl implements BookService {

    @Override
    public List<Book> findBookByAuthor(String author) {
        List<Book> books = new ArrayList<>();

        if ("mkyong".equals(author)) {
            books.add(new Book("mkyong in action"));
            books.add(new Book("abc in action"));
            books.add(new Book("bot"));
        }

        return books;
    }

   //implements other methods...

}

3.2単体テストを再度更新します。

AuthorServiceTest.java

package com.mkyong.mock;

import com.mkyong.examples.mock.AuthorServiceImpl;
import com.mkyong.examples.mock.FakeBookValidatorService;
import org.junit.Test;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class AuthorServiceTest {

    @Test
    public void test__total__book__by__mock() {

       //1. Setup
        AuthorServiceImpl obj = new AuthorServiceImpl();

       /** BookServiceImpl bookService = new BookServiceImpl();
        bookService.setBookDao(new BookDaoImpl());
        obj.setBookService(bookService);** /
        obj.setBookService(new MockBookServiceImpl());
        obj.setBookValidatorService(new FakeBookValidatorService());

       //2. Test method
        int qty = obj.getTotalBooks("mkyong");

       //3. Verify result
        assertThat(qty, is(2));

    }

}

上記の単体テストははるかに優れていて、高速で、分離されており(データベースがなくなった)、テスト条件(データ)は常に同じです。

3.3しかし、上記のように手動でモックオブジェクトを作成するにはいくつかの欠点があります:

  1. 最後に、多くのモックオブジェクト(クラス)を作成することができます.

単体テスト目的。

  1. インターフェイスに多数のメソッドが含まれている場合、それぞれのメソッドをオーバーライドする必要があります.

それら。

  1. まだまだ仕事が多いし、面倒です!

3.4

ソリューション

+

Mockito

を試してみましょう。

ユニットテスト – Mockito

4.1ユニットテストをもう一度更新します。今回は、Mockitoフレームワークを介してモックオブジェクトを作成します。

pom.xml

    <dependency>
            <groupId>org.mockito</groupId>
            <artifactId>mockito-core</artifactId>
            <version>2.0.73-beta</version>
    </dependency>

AuthorServiceTest.java

package com.mkyong.mock;

import com.mkyong.examples.mock.AuthorServiceImpl;
import com.mkyong.examples.mock.Book;
import com.mkyong.examples.mock.BookServiceImpl;
import com.mkyong.examples.mock.FakeBookValidatorService;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

public class AuthorServiceTest {

        @Test
        public void test__total__book__by__mockito() {

           //1. Setup
            List<Book> books = Arrays.asList(
                    new Book("mkyong in action"),
                    new Book("abc in action"),
                    new Book("bot"));

            BookServiceImpl mockito = mock(BookServiceImpl.class);

           //if the author is "mkyong", then return a 'books' object.
            when(mockito.findBookByAuthor("mkyong")).thenReturn(books);

            AuthorServiceImpl obj = new AuthorServiceImpl();
            obj.setBookService(mockito);
            obj.setBookValidatorService(new FakeBookValidatorService());

           //2. Test method
            int qty = obj.getTotalBooks("mkyong");

           //3. Verify result
            assertThat(qty, is(2));

        }

}

完了しました。あなたのフィードバックは高く評価されます

モバイルバージョンを終了