ユニットテストの概要


最初のプロジェクトではユニットテストはなく、基本的には自分でいろいろな方法でテストを実現しています.例えばコードを修正して、測定してから変更します.例えば、ユーザーの操作を直接シミュレートし、ブラックボックスでテストし、対応する論理があるかどうか、状態が変わっているかどうかを自分で見ます.
これらの方法にはいくつかの欠点があります.
  • テストが不完全で、いくつかの隠れた穴が掘られています
  • コードテストを変更し、戻ってくるときに新しいバグ
  • を導入する可能性があります.
  • 手動テスト比較時間
  • 次回需要を変更する場合は、再度手動で
  • をテストする必要があります.
    この中で何度も手作業でテストするのはつらいので、時間がもったいないです.以前は1つのロジックが多く、构造対象が复雑だったため、JUnitでテストを书くだけの仕事量が大きかったため、ユニットテストは続けられなかった.その後導入されたmockitoフレームワークは、新しいコードのテストに使用され、powermockは以前のコードテストに使用された.次にmockitoとpowermockフレームワークを紹介し、なぜこの2つのフレームワークを使うのかがわかります.
    Mockito
    mockitoは比較的広く使われているmockフレームワークです.mock技術の目的と役割は、アプリケーションで容易に構築されないオブジェクトや複雑なオブジェクトをシミュレートし、テストをテスト境界以外のオブジェクトから隔離することである.使い方を説明するために、まず基本オブジェクトを導入します
    public class User {
        private int userId;
        private ComplexObject complexObject;
        
        public int getUserId() {
            return userId;
        }
        //... construction getter
    }
    public class Service {
        public boolean checkUser(User user) {
            if(user.getUserId() < 100){
                return true;
            }
            return false;
        }
    }

    デフォルトのstatic import
    import static org.mockito.Mockito.*;
    import static org.junit.Assert.*;

    Mock Service#checkUserメソッドをテストする場合は、Userオブジェクトを構築します.ComplexObjectの構造が複雑であると仮定し,mockを用いなければテストは一歩も進まない.mockitoが偽のUserをどのように構築してテストしたのかを見てみましょう.
    @Test
    public void testCheckUser() throws Exception {
        Service service = new Service();
        User user = mock(User.class);
        when(user.getUserId()).thenReturn(2);
        boolean checkResult = service.checkUser(user);
        assertTrue(checkResult);
    }

    mockメソッドだけでいいのがわかりますが、getUserIdメソッドの戻り値を設定すればいいです.whenの文法は理解しやすいので、説明しません.上のwhen文も
    doReturn(2).when(user).getUserId();
    

    この例では,この2つのwhenの書き方はいずれも可能である.一つの方法をシミュレートするには、以下のいくつかの方法があります.
  • doReturn
  • doCallRealMethod
  • doNothing
  • doThrow
  • doAnswer

  • もちろんthenXXXという形もあります.
    Spy
    spyはmockに似ていて、オブジェクトをシミュレートしています.しかしmockはすべてのメソッドを引き継ぎ,spyはデフォルト呼び出しオブジェクトのメソッドである.オブジェクトをmockしてからメソッドごとにdoCallRealMethodを呼び出すと、spyがオブジェクトを出力することに相当します.したがってspyとmockは初期シミュレーションオブジェクトのデフォルト設定が異なるだけで、他の動作は同じです.
    Annotation
    注記を直接使用してmockを実現できます.
    @Mock
    User user;
    
    @Before
    public void initMocks() {
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    public void testCheckUser() throws Exception {
        Service service = new Service();
        doReturn(2).when(user).getUserId();
        boolean checkResult = service.checkUser(user);
        assertTrue(checkResult);
    }

    これは、initMocks(this)を呼び出して注入する必要があり、ここでは@Beforeを介して、@RunWithを呼び出してもよいし、initMocks方法を呼び出してもよい.
    Spy注記も使用できます.
    @Spy User user;

    もう1つの注釈は@InjectMocksであり、これはオブジェクトを他のオブジェクトに注入することができる.コードを少し追加します.
    public class ComplexObject {
        @Override
        public String toString() {
            return "Complex lhcpig";
        }
        //...
    }
    public class Service {
        public String handleUser(User user){
            return user.getComplexObject() + "";
        }
        //...
    }
    public class TestService {
    
        @InjectMocks
        User user;
        @Spy
        ComplexObject complexObject;
    
        @Before
        public void initMocks() {
            MockitoAnnotations.initMocks(this);
        }
    
        @Test
        public void testHandleUser() throws Exception {
            Service service = new Service();
            String s = service.handleUser(user);
            assertThat(s, is("Complex lhcpig"));
        }
        //...
    }
  • 注1:ここでは前のtestと競合していますが、Userの注釈が異なるため、最初のtestはNotAMockExceptionまたはMissingMethodInvocationException異常を報告します.
  • 注2:ここでSpyを使うと、追加コードを使わずにCallRealMethodになります.

  • Verify
    これは,メソッドが呼び出されたか,呼び出しがタイムアウトしたか,何回呼び出されたかを判断するためのテストである.
    @Test
    public void testCheckUser() throws Exception {
        Service service = new Service();
        when(user.getUserId()).thenReturn(2);
        boolean checkResult = service.checkUser(user);
        assertTrue(checkResult);
        verify(user).getUserId();
        verify(user, timeout(100)).getUserId();
        user.getUserId();
        verify(user, times(2)).getUserId();
    }

    メソッドにパラメータがある場合は、パラメータを検証することもできます.ここでは概要だけですが、Mockitoを詳しく知りたいなら、公式サイトのドキュメントを見ることをお勧めします.
    PowerMock
    Mockitoはfinalメソッド,プライベートメソッド,静的メソッドをサポートせず,PowerMockはサポートする.ここでも紹介します.しかし、プロジェクトでの使用は推奨されません.PowerMockを使用してテストする必要がある場合は、コードのテスト性が悪いことを示し、コードを改善する必要があります.通常は、履歴残存コードやサードパーティライブラリ関連テストの場合に使用する必要があります.
    次は使用方法です.
    @RunWith(PowerMockRunner.class)
    @PrepareForTest( { YourClassWithEgStaticMethod.class })
    public class YourTestCase {
    ...
    }

    例をあげると,みんなは理解した.
    @RunWith(PowerMockRunner.class)
    @PrepareForTest( { Service.class })
    public class TestService {
    
        @Before
        public void initMocks() {
            mockStatic(Service.class);
        }
    
        @Test
        public void testTestStaticFinal() throws Exception {
            PowerMockito.when(Service.testStaticFinal()).thenReturn("mock1");
            assertEquals("mock1", Service.testStaticFinal());
        }
    
        @Test
        public void testPrivate() throws Exception {
            Service t = mock(Service.class);
            PowerMockito.when(t, "testPrivate").thenReturn("xxx");
            doCallRealMethod().when(t).testPrivateForPublic();
            assertEquals("xxx", t.testPrivateForPublic());
        }
    
        @Test
        public void testTestPrivateWithArg() throws Exception {
            Service t = spy(new Service());
            String arg = "dd";
            PowerMockito.when(t, "testPrivateWithArg", arg).thenReturn("lhc");
            assertEquals("lhc", t.getTestPrivateWithArg(arg));
        }
    }
    public class Service {
    
        public static final String testStaticFinal() {
            System.out.println("testStaticFinal");
            return "static final";
        }
    
        private String testPrivate() {
            System.out.println("testPrivate");
            return "private";
        }
    
        public String testPrivateForPublic() {
            System.out.println("testPrivateForPublic");
            return testPrivate();
        }
    
        private String testPrivateWithArg(String arg) {
            System.out.println("testPrivateWithArg");
            return arg + "x";
        }
    }

    プライベートメソッドをPowerMockでテストすると、名前を変更するのが面倒になり、再構築してもテスト例に影響を与える可能性があります.PowerMockの正しい使い方は、なるべく使わないことです.
    プライベートメソッドを呼び出すのを反射するので、書き方はmockitoほど優雅ではありません.私がここで使っているのはMockitoベースのPowerMockなので、上記のspy、whenなどを混ぜて使うことができます.もちろんPowerMockには他のmockフレームワーク(EasyMock)に基づく拡張もありますが、ここではこれ以上説明しません.
    テストをより効率的にするには、テストフレームワークが次のように、テスト可能なコードを書くことが最も重要です.