しむしむてるるの日記&雑談 同人誌の進捗やら仕事のあれこれやら書いています。

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
[ --/--/-- --:-- ] スポンサー広告 | TB(-) | CM(-)

ユニットテストって具体的にどうやるのか?

今の業務を始めて、JUnitやNightlyなんて言葉を聞く様になりました。

JUnitはJavaのユニットテストを行うフレームワークで、
Nightlyは毎晩自動でビルド&テストを行うシステム(?)の事です。
プログラムの仕事には、実際にコードを書いていく実装以外にも
『ユニット(単体)テスト』や『結合テスト』などの動作テストがあって、
実際にそれを行うために使うのがJUnitやNightlyな訳です。

と、そこまでは良いんです。
概念的な事や概要は今までの知識や経験で何となく分かりますから。
ただ、『実際にどうやるのか?』それが問題です。
と言っても、フレームワークやらツールは使い方を調べれば良いからそんなに問題にはなりません。
実際の問題は、『ユニットテストをどうやるのか?』です。

単体テストは、単純に考えればメソッド(関数)が正しく動作するかをテストする事になります。
具体的には、引数にいろんなパラメータを入れて、仕様通りの結果が得られるか?
それをテストするわけです。
まぁ、それだけなら別にどうってこと無いと思います。
要はfunc(a,b)と言う関数が a/b と言う除算をするとしたら、
void test(void){
// 0/1なら例外は発生せず、結果が0になる事を期待する
try{
int res = func( 0, 1);
if( res != 0 ) print( "Return Error\n");
}catch{
print( "Exception Error\n");
}
// 1/0なら例外が発生する事を期待する
try{
int res = func( 1, 0);
print( "Not Exception Error\n");
}catch{
}
// 2/1なら例外は発生せず、結果が2になる事を期待する
try{
int res = func( 2, 1);
if( res != 1 ) print( "Return Error\n");
}catch{
print( "Exception Error\n");
}
// 1/2なら例外は発生せず、結果が0.5になる事を期待する
try{
int res = func( 1, 2);
if( res != 0.5 ) print( "Return Error\n");
}catch{
print( "Exception Error\n");
}
}
※このコードは仮想言語のものです

と言う感じでテストすれば良い訳です。
この場合は次の4つのテストをしていることになります。
 ・ 割られる数が0の場合(例外とならず、正しく演算されるか?)
 ・ 割る数が0の場合(例外が発生するか?)
 ・ 除算結果が整数の場合(正しく演算されるか?)
 ・ 除算結果が少数の場合(少数の結果が返ってくるか?)
期待通りの動作をしないとメッセージが出力されるようになります。
実際のコードは、テスト方針や使用する言語・フレームワークで異なると思いますが、基本の考え方はこんな感じになると思います。
もっと詳しくテストするなら、割る数や割られる数が-(負の数)の場合とかも入れる必要があるでしょうけどね。

まぁ、このくらいであれば、悩むとしてもテスト項目を決める事ぐらいでしょう。

では、メソッド(関数)が内部で別のクラスを使って処理をしたり、
外部のDBや通信、ファイルを使用している場合はどうやってテストすれば良いのでしょう?
概念としては、『スタブ』を作って、それに差し替えれば良いことになります。
『スタブ』を作る事はそんなに難しくありません。
ただ、『差し替え』をどうやるのか? が問題です。

と言う訳で、次回はその『差し替え』について考えてみようと思います。
スポンサーサイト
[ 2013/02/05 00:37 ] プログラム | TB(0) | CM(0)

指定したソースファイルから使用するのに必要なファイルを抽出

今回はちょっとしたコードを載せてみます。

iOSの仕事で、他のアプリで使っている一部の機能を使う必要がでたのですが、
その機能がどのソースを読み込んでいるのか追いきれません。
なので、指定したファイルを起点に、importしているファイルを追って行って、
組み込まなきゃ行けないソースを全て抽出するコードを組んでみました。
と言っても、ちょちょいと1時間くらいで作ったので汎用性はありませんが...

とりあえず、コードを掲載。

【importlist.php】

$lines = file( 'php://stdin', FILE_IGNORE_NEW_LINES);

$targetfile = $argv[1];
$sources = array();
$importlists = array();

// read import data
for( $i=0; $i $elem = split( ":", $lines[$i]);
$filename = preg_replace( "/\.[mh]/", "", $elem[0]);
// space cut
$import = preg_replace( "/[ \t]+/", "", $elem[1]);
// comment
if( substr( $import, 0, 2)=="//" ) continue;

$res = preg_match( '/".+\.h"/', $import, $import);
if( $res==0 ) continue;
$importfilename = "";
foreach( $import as $c ){ $importfilename .= $c; }
$importfilename = preg_replace( "/\.[mh]/", "", $importfilename);
$importfilename = preg_replace( "/\"/", "", $importfilename);

if( isset($sources[$filename]) ){
$arr = $sources[$filename];
array_push( $arr, $importfilename);
$sources[$filename] = $arr;
print( "*add filename=" . $filename . ", importfilename=" . $importfilename . "\n");
}else{
$arr = array($importfilename);
$sources[$filename] = $arr;
print( "*new filename=" . $filename . ", importfilename=" . $importfilename . "\n");
}
}

// output all import list
print( "========== read import list ==========\n");
print_r( $sources);
print( "========== read import list ==========\n");

hirSearch($targetfile);

// output used importfile
print( "========== import list ==========\n");
foreach( $importlists as $filename ){
print( $filename . "\n");
}
print( "========== import list ==========\n");

function hirSearch( $filename){
global $sources;
global $importlists;
if( !in_array( $filename, $importlists) ){
array_push( $importlists, $filename);
if( isset($sources[$filename]) ){
foreach( $sources[$filename] as $importfile ){
hirSearch( $importfile);
}
}else{
print( "*message not found -> " . $filename . "\n");
}
}
}

?>


使い方は、
 1. 抽出したいアプリの全ソースコードを同一ディレクトリにコピーします。
 2. 次のコマンドを実行します。
> grep import * | php importlist.php target

これで、target.h/target.mを使うのに必要なソースが全て抽出できる...と思います。

処理としては大したことしてませんが、簡単に説明すると...
 1. 始めにgrepで前ファイルのimport行を抽出した結果を取得
 2. grep結果から各ファイルでimportしているファイルを抽出し、配列化
 3. 指定したファイルで使っているimportを取得
 4. 取得したimportをimportリストに追加
 5. 取得したimportを指定ファイルに変更
 6. 読み込めるimportが無くなるまで3-5の繰り返し
 7. importリストを出力
こんな感じです。

あまり使う様な機会は無いと思いますが、
何かの役に立つかもしれないのでメモ的に残しておきます。
[ 2012/09/18 05:49 ] プログラム | TB(0) | CM(1)

プログラムの練習問題3-画面に*を三角形に表示させる3-

プログラムコードの組み方を考える記事の第3回。
今回は、
          *
*****
*********
*************
*****************
*********************

と画面に表示するプログラムを考えたいと思います。

ちなみに、前回のプログラムの完成系はこれでした。
public class Main2 {
public static void main( String[] args) {
int lineNum = 6; // 表示を6行に設定
int spaceNum = lineNum - 1;
int hosiNum = 1;
for( int i=0; i<lineNum; i++){
for( int j=0; j<spaceNum; j++){
System.out.print(" ");
}
for( int j=0; j<hosiNum; j++){
System.out.print("*");
}
System.out.println("");
spaceNum--;
hosiNum+=2;
}
}
}

このプログラムを元にして、今回の表示をしてみます。

さて、どこを修正すれば良いのでしょう?
それは、前回の表示結果と今回との違いが分かれば比較的見つけ易いと思います。
では、それは何でしょうか?

それは、*の数が左右に1つずつ増えているのが2つずつに変わっている事です。
そうなると、まず変更するのは*を表示する数を増やしている所です。
*の数を決めているのは hosiNum ですので、その変数を変更している部分を変更することになります。
上のプログラムでは、15行目ですね。
ここを hosiNum += 2*2; と変えます。
"2*2"でなく、"4"としても問題ありませんが、この後の事を考えてこういった記述にしています。

さて、これで完成でしょうか?
試しに変更後のプログラムを実行してみましょう。
     *
*****
*********
*************
*****************
*********************

と、こんな形になりました(^^;
*の数は問題ないけど、左側のスペースが上手くいっていません。

なぜなら、*の数は左側に2つ増えるのに、スペースは1つ減るだけだからです。
と言う訳で、スペースの数も2つずつ減るようにしましょう。
スペースの数は spaceNum で決まるので、14行目を spaceNum -= 2; と修正します。
ですが、これだけだと前回の行数を変えた時と同じ様な現象が出てしまいます。
なぜでしょう?

それは、スペースの初期値。1行目に入るスペースの数が正しくないからです。
では、正しいスペースの数はいくつか...
それは単純に、数えれば分かりますね。(^^;
正解は10個です。

と言う訳で、4行目を int spaceNum = 10; ... としたい所ですが、ちょっと待ちましょう。
折角表示する行数を簡単に変更出来るようにしているのですから、
今回もそうしたい所です。
さて、どうすれば良いか...答えは簡単です。
int spaceNum = ( lineNum - 1 ) * 2;
と、"*2"して倍にすれば良いのです。

さぁ~これで完成です。プログラムは次のようになりました。
public class Main3 {
public static void main( String[] args) {
int lineNum = 6;
int spaceNum = (lineNum-1)*2;
int hosiNum = 1;
for( int i=0; i<lineNum; i++){
for( int j=0; j<spaceNum; j++){
System.out.print(" ");
}
for( int j=0; j<hosiNum; j++){
System.out.print("*");
}
System.out.println("");
spaceNum-=2;
hosiNum+=2*2;
}
}
}

さて、ここからもうひと捻りしてみましょう。

まず、*の増加する数も可変にしてみます。
可変にすると言う事は、変数を使って変えられるようにすると言う事です。
今回は stepNum という変数を新たに作成します。
とりあえず4行目あたりに追加しましょう。
int stepNum = 3;
数はさらに増やして3つずつ増えるように"3"としてみました。
これで*が3つずつ増えるようになるはずです。

そして、次に実際に増やす処理ですが...
元のプログラムの14行目・15行目になります。
もう分かりますね?
ここで、スペースの数を減らし、*の数を増やしているのです。
そして、15行目をわざわざ 2*2 としたのもこの為です。
変更後のコードはこうなります。
spaceNum -= stepNum;
hosiNum += 2*stepNum;
そして、もう一つ。
4行目(1行目のスペースの数)も変えましょう。
int spaceNum = (lineNum-1)*stepNum;
さ~これで完成です。
最終的に出来たコードはこんな感じです。
public class Main3 {
public static void main( String[] args) {
int lineNum = 6;
int stepNum = 3;
int spaceNum = (lineNum-1)*stepNum;
int hosiNum = 1;
for( int i=0; i<lineNum; i++){
for( int j=0; j<spaceNum; j++){
System.out.print(" ");
}
for( int j=0; j<hosiNum; j++){
System.out.print("*");
}
System.out.println("");
spaceNum-=stepNum;
hosiNum+=2*stepNum;
}
}
}

そして、実行結果がこれ。
               *
*******
*************
*******************
*************************
*******************************

コード内のlineNumやstepNumを変えると、それに応じて行数や形が上手く変わるはずです。

最後にlineNumやstepNumの数を実行時に指定出来る(コマンド引数で与える)ようにしたかったのですが...
思ったよりも長くなってしまったので、それは次回にしたいと思います。

<前回:プログラムの練習問題2-画面に*を三角形に表示させる2-
[ 2012/05/24 23:24 ] プログラム | TB(1) | CM(0)

プログラムの練習問題2-画面に*を三角形に表示させる2-

プログラムコードの組み方を考える記事の第2回。
今回は、
     *     
***
*****
*******
*********
***********
と画面に表示するプログラムを考えたいと思います。

とりあえず、1行ずつ表示させてみましょうか?
public class Main {
public static void main( String[] args) {
System.out.println(" *");
System.out.println(" ***");
System.out.println(" *****");
System.out.println(" *******");
System.out.println(" *********");
System.out.println("***********");
}
}
単純に表示させたい文字をprintlnで表示させてるだけです。
これで一応表示はできました。
できました...けど、プログラムとしてどうなの?って感じですね(^^;

もう少しスマートにするために、表示内容を解析してみましょう。
まず、表示内容ですが" "と"*"だけの組み合わせになっています。
そして、1行目は" "を5つと"*"を1つ表示させています。
2行目は" "を4つと"*"を3つ。
同様に3行目は" "を3つと"*"を5つ
.....
何か法則が見えてきませんか?
 法則1 " "(スペース)の数は行数が増える度に1つずつ減っている
 法則2 "*"の数は行数が増える度に2つずつ増えている
この2つの法則がありますね。

でも、これだけだとプログラムまで落とせません。
なぜ?
だって、これだけだと1行目の表示が出来ませんから、
1行目に表示させる" "と"*"の数が分からないとプログラムが書けません。

では、それを考えてみましょう。
まず"*"の数ですが、これは単純ですね。1つ表示させれば良いのですから。
そして" "の数は5つです。
さて、ではこの条件でプログラムを作ってみましょう。
と言っても、いきなりだとどう書けば良いのか分からないかもしれません。
なので、実際にコードに落とす前にフローを考えてみます。
 1. 1行目に表示させる" "と"*"の数を設定。
   " "の数はspaceNum,"*"の数はhosiNumと言う変数名とする。
 2. spaceNumの数だけ" "を表示
 3. hosiNumの数だけ"*"を表示
 4. 改行する(2・3は1行に続けて表示するだけなので改行が必要)
 5. 次の行の表示の為にspaceNumとhosiNumの数を変更
   spaceNumは1つ減らす。
   hosiNumは2つ増やす。
 6. 2~4を表示させたい行数分繰り返す。
これで、プログラムが書けそうです。
そして、実際にプログラムにするとこんな感じになります。
public class Main2 {
public static void main( String[] args) {
int spaceNum = 5;
int hosiNum = 1;
for( int i=0; i<6; i++){
for( int j=0; j<spaceNum; j++){
System.out.print(" ");
}
for( int j=0; j<hosiNum; j++){
System.out.print("*");
}
System.out.println("");
spaceNum--;
hosiNum+=2;
}
}
}

ありゃ? なんか、始めのプログラムより長くなってしまいました。(^^;
でも、それで良いんです。
それはなぜでしょう?

その答えは表示内容の変更が簡単に行えるかどうかです。
例えば、例題は6行の表示でしたが、10行の表示にするにはどうすれば良いのでしょう?
始めのプログラムであれば、println文を4つ追加する必要があります。
では、2つ目のプログラムではどうでしょう?
基本的には5行目のfor文の繰り返し回数を6から10に変えるだけです。
ね?簡単でしょう?
ただし、今回のプログラムには罠があります。
試しに10行表示のプログラムにしてみましょう。
public class Main2 {
public static void main( String[] args) {
int spaceNum = 5;
int hosiNum = 1;
for( int i=0; i<10; i++){
for( int j=0; j<spaceNum; j++){
System.out.print(" ");
}
for( int j=0; j<hosiNum; j++){
System.out.print("*");
}
System.out.println("");
spaceNum--;
hosiNum+=2;
}
}
}

どうですか? ちゃんと表示されましたか?
表示内容が
     *
***
*****
*******
*********
***********
*************
***************
*****************
*******************

こんな感じになっていませんか?
途中までは上手くいっているのに、後半が崩れちゃってます。
なぜでしょう?

結果をよく見ると、後半は表示して欲しい" "が抜けていることに気付きませんか?
つまり、" "の数が足りないのです。
なぜなら、はじめに『spaceNum=5』としてしまっているからです。
1行表示する度に1つ減りますから、5行分しか表示出来ないのです。
と言う事は、10行だと『spaceNum=9』とすれば良い事になります。
(最後の行にスペースは要らないので"表示行数-1"個となる)
もちろん、直接3行目を『spaceNum=9』としても良いのですが、
表示させたい行数も変数に入れてしまいましょう。
そうすると、こうなります。
public class Main2 {
public static void main( String[] args) {
int lineNum = 10;
int spaceNum = lineNum - 1;
int hosiNum = 1;
for( int i=0; i<lineNum; i++){
for( int j=0; j<spaceNum; j++){
System.out.print(" ");
}
for( int j=0; j<hosiNum; j++){
System.out.print("*");
}
System.out.println("");
spaceNum--;
hosiNum+=2;
}
}
}

変数lineNumを使って、1行目のスペースの数の設定とループ回数を指定できるようにしました。
これで、lineNumの数を変えるだけで表示する行数をいくらでも変えられるようになります。

どうですか? 少しはプログラムっぽくなってきていませんか?
表示する行数の変更が始めと比べ物にならないくらい簡単になっていると思います。

今回は行数の可変に対応しましたが、表示内容を可変にする事も簡単にできます。
例えば
         *
***
*******
***********
***************
*******************

こんな感じに少し横長の3角形にする事も簡単にできます。

と言う事で、次回は上のような横長3角形を作ってみましょう。
ついでにコマンドラインで表示したい行数を入力できるようにもしてみましょう。
lineNumをコマンドライン引数から取得するプログラムです。

では、また次回。

<前回:プログラムの練習問題1-画面に*を三角形に表示させる-
[ 2012/04/22 05:09 ] プログラム | TB(3) | CM(0)

プログラムの練習問題1-画面に*を三角形に表示させる-

今日は、初心者的プログラムのコードを載せてみます。
プログラムの初心者は命令文の使い方は分かっても、アルゴリズムや考え方で躓く事が多いように思います。
なので、このblogでは簡単なコードと考え方も少しずつ載せていこうと思います。

さて、今回のお題は...
「*(アスタリスク)を三角形に表示させるプログラムを組む」です。
表示結果としては下のようになります。
*
**
***
****
*****
******
*******

さて、どんなプログラムになるでしょう?

まず始めに考えられるのはこんなコードでしょう。
public class PrintTest{
public static void main( String[] args){
System.out.println("*"); // 1行目の表示
System.out.println("**"); // 2行目の表示
System.out.println("***"); // 3行目の表示
System.out.println("****");
System.out.println("*****");
System.out.println("******");
System.out.println("*******");// 7行目の表示
}
}

単純明快ですね。何も考える必要がありません。
表示結果そのものを1行ずつ表示しているだけです。

ここで、もう少し考えてみます。
表示結果をみると...1行目は*が1つ、2行目は*が2つ......7行目は*が7つとなっている事が分かります。
つまり、行数と*の数が同じなのです。
1行目は*を1つ表示して改行。
2行目は*を2つ表示して改行。
...
7行目は*を7つ表示して改行。
となるコードを考えます。
その考え方でコードを組むと...
public class PrintTest2{
public static void main( String[] args){
for( int i=1; i<=7; i++){ // 行数ループ(iは何行目かを示す)
// i個の*を表示するfor文
for( int j=1; j<=i; j++){ // 文字数ループ(i回ループ)
System.out.print("*"); // *を表示(改行なし)
}
System.out.println(""); // *を表示し終わったら改行
}
}
}

となります。

そして、もう1つ...
行が1つ進むと*の数が1つ増えていると考える事も出来ます。
public class PrintTest3{
public static void main( String[] args){
String str=""; // 文字列の初期化
for( int i=1; i<=7; i++){ // 行数ループ(iは何行目かを示す)
str = str + "*"; // 保持している文字列に*を1つ追加
System.out.println(str); // 文字列を表示&改行
}
}
}

こんなコードも書けます。
これは、Stringクラスを用いて、保持している文字列に*を1つずつ追加して表示させています。
コードとしてはこれが一番短くなりますね。
そして、2つめのfor文の入れ子より読み易い気がします。

プログラムとしては、変更に強そうな2つめが良い気がしますが、
今回の問題の最適解は3つめでしょうか?
このあたりは人それぞれ、コードを書く人のセンスになりますが。

と言ったところで1回目のプログラム練習を終わります。
次回は、
     *     
***
*****
*******
*********
***********

と画面に表示するプログラムを考えたいと思います。

<次回:プログラムの練習問題2-画面に*を三角形に表示させる2-
[ 2012/03/04 07:46 ] プログラム | TB(0) | CM(0)
FC2カウンター
カレンダー
08 | 2017/09 | 10
- - - - - 1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Twitter@sweetsblast
過去ログ

2017年 08月 【1件】
2017年 06月 【3件】
2017年 05月 【3件】
2017年 04月 【3件】
2017年 03月 【5件】
2017年 01月 【1件】
2016年 09月 【2件】
2016年 04月 【2件】
2016年 03月 【2件】
2016年 01月 【5件】
2015年 12月 【3件】
2014年 05月 【1件】
2014年 04月 【1件】
2013年 12月 【1件】
2013年 03月 【4件】
2013年 02月 【3件】
2013年 01月 【1件】
2012年 12月 【3件】
2012年 11月 【4件】
2012年 10月 【2件】
2012年 09月 【4件】
2012年 08月 【2件】
2012年 07月 【3件】
2012年 06月 【11件】
2012年 05月 【11件】
2012年 04月 【9件】
2012年 03月 【15件】
2012年 02月 【17件】
2012年 01月 【5件】
2011年 12月 【14件】
2011年 11月 【11件】
2011年 10月 【19件】
2011年 09月 【10件】
2011年 08月 【4件】
2011年 07月 【11件】
2011年 06月 【4件】
2011年 05月 【1件】
2011年 04月 【17件】
2011年 03月 【29件】
2011年 02月 【24件】
2011年 01月 【30件】
2010年 12月 【30件】
2010年 11月 【22件】
2010年 10月 【26件】
2010年 09月 【27件】
2010年 08月 【30件】
2010年 07月 【27件】
2010年 06月 【24件】
2010年 05月 【7件】
2010年 04月 【6件】
2010年 03月 【3件】
2010年 02月 【6件】
2010年 01月 【8件】
2009年 12月 【8件】
2009年 11月 【5件】
2009年 10月 【7件】
2009年 09月 【18件】
2009年 08月 【22件】
2009年 07月 【14件】
2009年 06月 【16件】
2009年 05月 【28件】
2009年 04月 【25件】
2009年 03月 【5件】
2009年 01月 【2件】
2008年 12月 【1件】
2008年 11月 【2件】
2008年 10月 【3件】
2008年 09月 【6件】
2008年 08月 【3件】
2008年 07月 【2件】
2008年 06月 【2件】
2008年 05月 【3件】
2008年 04月 【4件】
2008年 03月 【11件】
2008年 02月 【12件】
2008年 01月 【7件】
2007年 12月 【8件】
2007年 11月 【5件】
2007年 10月 【8件】
2007年 09月 【6件】
2007年 08月 【15件】
2007年 07月 【10件】
2007年 06月 【14件】
2007年 05月 【12件】
2007年 04月 【10件】
2007年 03月 【7件】
2007年 02月 【19件】
2007年 01月 【18件】
2006年 12月 【25件】
2006年 11月 【27件】
2006年 10月 【19件】
2006年 09月 【26件】
2006年 08月 【12件】
2006年 07月 【5件】



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。