月曜日, 7月 14, 2014

モックのDI

IoCコンテナを使えば,テスト用にドライバ/スタブを容易にDIできる.
当然のことなのだが,意外にこの利点をあえて使わない(?)テストケースを書いてくることがままある.これを使えば当然テストコードはかなり可読性が高くなるので,使わない手はないはずだが.

以下はモックのDIの参考例.
以下の例では,DataDumpServiceのインタフェースを介してConsoleDataDumpService並びにDataNodeNodeIFインタフェースを介して テスト用データを持つDataNodeをユニットテスト中にDIする.

DataDumpServiceインタフェース

package org.tanuneko;

public interface DataDumpService {

    public void dump( Object obj );

}

ConsoleDumpServiceクラス

package org.tanuneko;

import org.springframework.stereotype.Service;

@Service
public class ConsoleDataDumpService implements DataDumpService {

    public void dump( Object obj ) {
        System.out.println( obj );
    }
}

NodeIFインタフェース

package org.tanuneko;

public interface NodeIF<X> {

    public X getData();
}

DataNodeクラス

package org.tanuneko;

public class DataNode<X> implements NodeIF {

    private X data;

    public DataNode( X data ) {
        this.data = data;
    }

    public X getData() {
        return data;
    }
}

AppConfig(非テスト用)

package org.tanuneko;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan("org.tanuneko")
public class AppConfig {

    @Bean
    public NodeIF data() {
        return new DataNode( "This is prod" );
    }
}

App(非テスト用)

package org.tanuneko;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class App {

    public App() {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register( AppConfig.class );
        ctx.refresh();
        NodeIF node = ctx.getBean( DataNode.class );
        System.out.println( node.getData() );
        DataDumpService srv = ctx.getBean( ConsoleDataDumpService.class );
        srv.dump( node.getData() );

    }

    public static void main( String args[] ) {

        App a = new App();

    }
}

テストアップランチャ

package org.tanuneko;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;


@Component
public class TestAppLauncher {

    @Autowired
    DataDumpService dp;

    @Autowired
    NodeIF dataNode;

}

AppConfig(テスト用)

package org.tanuneko;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;


@Configuration
@ComponentScan("org.tanuneko")
public class AppTestConfig {

    @Bean
    public NodeIF data() {
        return new DataNode( "This is test" );
    }

}

テストクラス

package org.tanuneko;

import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;


public class AppTest {

    private static TestAppLauncher testApp;

    @BeforeClass
    public static void init() {

        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
        ctx.register( AppTestConfig.class );
        ctx.refresh();
        testApp = ctx.getBean( TestAppLauncher.class );

    }

    @Test
    public void testDataNode() {

        testApp.dp.dump( testApp.dataNode.getData() );

    }

}

0 件のコメント: