社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

JUnit Enclosed によるテストケースのグループ化

既に存在しているテストクラスに新しいテストケースを追加するとき、どの位置に入れようか迷うときがあります。
出来れば、後で見たときに分かりやすい位置に入れたいですが、そもそも整理されていなければそれも難しいです。そこで Enclosedを使うことで、テストケースのグループ化が可能です。

@RunWith(Enclosed.class)
public class RunWithTest {
	public static class TestForNumber {
	    @Test
            public void additionTest() {
                int actual = 1 + 2;
                assertThat(actual, is(3)); 
            }
		
	    @Test
	    public void subtractionTest() {
	        int actual = 1 - 2;
                assertThat(actual, is(-1)); 
	    }
	}
	
	public static class TestForCharacter {
	    @Test
            public void additionTest() {
                String actual = "a" + "b";
                assertThat(actual, is("ab")); 
            }
		
	    @Test
	    public void replaceTest() {
	        String actual = "a".replace("a", "b");
                assertThat(actual, is("b")); 
	    }
	}
}

どのような観点でグループ化するか迷いところですが、いくつかヒントはありそうです。

  • 共通のデータで分ける
  • 共通の状態で分ける
  • コンストラクタのテストを分ける など

テスト結果も以下のようにグループ化されて表示されます。
f:id:blueskyarea:20190717233754p:plain

Python CUIで迷路生成(2)

内壁を生成するところまで。
棒倒し法により生成するが、その手順は
1. 迷路全体を構成する2次元配列を、幅高さ5以上の奇数で生成する
2. 迷路の外周を壁とし、それ以外を通路とする
3. 外周の内側に基準となる壁(棒)を1セルおき(x, y ともに偶数の座標)に配置する
4. 内側の壁(棒)を走査し、ランダムな方向に倒して壁とする
※ただし以下に当てはまる方向以外に倒す

  • 1行目の内側の壁以外では上方向に倒してはいけない
  • すでに棒が倒され壁になっている場合、その方向には倒してはいけない
import sys
import random

class Maze():
    PATH = 0
    WALL = 1

    def __init__(self, height, width):
        self.maze = []
        self.width = width
        self.height = height
        if (self.width % 2) == 0:
            self.width += 1
        if (self.height % 2) == 0:
            self.height += 1
    
    def set_outer_wall(self):
        for y in range(0, self.height):
            row = []
            for x in range(0, self.width):
                if (x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1):
                    cell = self.WALL
                else:
                    cell = self.PATH
                row.append(cell)
            self.maze.append(row)
        return self.maze

    def set_inner_wall(self):
        for x in range(2, self.width-1, 2):
            for y in range(2, self.height-1, 2):
                self.maze[y][x] = self.WALL
                while True:
                    wall_x = x
                    wall_y = y
                    if y == 2:
                        direction = random.randrange(0, 4)
                    else:
                        direction = random.randrange(0, 3)

                    if direction == 0:
                        wall_x += 1
                    elif direction == 1:
                        wall_y += 1
                    elif direction == 2:
                        wall_x -= 1
                    else:
                        wall_y -= 1
                    if self.maze[wall_y][wall_x] != self.WALL:
                        self.maze[wall_y][wall_x] = self.WALL
                        break
        return self.maze

    def print_maze(self):
        for row in self.maze:
            for cell in row:
                if cell == self.PATH:
                    print(' ', end='')
                elif cell == self.WALL:
                    print('#', end='')
            print()

args = sys.argv
maze = Maze(int(args[1]), int(args[2]))
maze.set_outer_wall()
maze.set_inner_wall()
maze.print_maze()

出力例

$ python create_maze.py 10 20
#####################
# #   #         # # #
# # # # # # ### # # #
#   #   # # #       #
# ##### ### # ##### #
#   #     # #     # #
# ##### ######### # #
#   #     #       # #
### # ### ##### ### #
#   #   #     #   # #
#####################

Java 例外(Exception) テスト

例外(Exception)のテストの書き方でよく知られているもので、Ruleアノテーションを用いた ExpectedException を使う方法があります。
例外のメッセージまで評価してくれるのがいいですね。

public class RuleTest {
	@Rule
	public ExpectedException expectedException = ExpectedException.none();

	@Test
	public void testThrowException() {
		expectedException.expect(RuntimeException.class);
		expectedException.expectMessage("Rule test");
		throw new RuntimeException("Rule test");
	}
}

Python CUIで迷路生成(1)

外壁を生成するところまでのステップ。
__init__
1. Maze(迷路) クラスを生成し、maze, width, height の変数を定義する
※第一引数で縦のサイズ(height)、第二引数で横のサイズ(width)を与える

set_outer_wall
2. row という配列にそのセルが壁なのか、通路なのかを格納していく
3. maze に1行ずつ(row) を格納していく

print_maze
4. maze に格納されている row を一つずつ取り出し、さらにセルを一つずつ取り出し、画面出力(壁か通路)させる

import sys
import random

class Maze():
    PATH = 0
    WALL = 1

    def __init__(self, height, width):
        self.maze = []
        self.width = width
        self.height = height
    
    def set_outer_wall(self):
        for y in range(0, self.height):
            row = []
            for x in range(0, self.width):
                if (x == 0 or y == 0 or x == self.width - 1 or y == self.height - 1):
                    cell = self.WALL
                else:
                    cell = self.PATH
                row.append(cell)
            self.maze.append(row)
        return self.maze

    def print_maze(self):
        for row in self.maze:
            for cell in row:
                if cell == self.PATH:
                    print(' ', end='')
                elif cell == self.WALL:
                    print('#', end='')
            print()

args = sys.argv
maze = Maze(int(args[1]), int(args[2]))
maze.set_outer_wall()
maze.print_maze()

出力例

python create_maze.py 10 20
####################
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
#                  #
####################

プログラマーとしてアルゴリズムを学ぶべきなのか

アルゴリズムとデータ構造
並び替え・検索はシステムのプログラムを書く上で基本的な動作に挙げられると思います。
それらには色んな種類があります。

ここで挙げるまでもないですが
並び替え

検索

そしてそれを実現するためのデータ構造があります。
データ構造

  • リスト
  • スタック、キュー
  • ツリー
  • グラフなど

アルゴリズムを実装する機会
これらを実際のプログラミングする機会において、実装したことはあるでしょうか。
プログラミングを習うための練習や、アルゴリズムに興味がある方であれば、実装経験がきっとあると思います。

ただ仕事でプログラミングを行うケースにおいて、こういったアルゴリズム自体を実装することはほとんど無いかもしれません。
世の中には便利なライブラリがたくさん開発されているためです。
並び替えなら、sort() と書けばソートしてくれるし、検索なら、get() と書けば必要なデータを探してくれます。

自分はプログラミングを仕事で始めたころ、ライブラリの存在をあまり知りませんでした。
つまり、何でも自分で実装しようとしていました。
そんなに複雑なものではなかったと思いますが、並び替えの実装をする必要がありました。
もちろん簡単には出来ませんでした。
しかしながら、試行錯誤しアルゴリズムを考え、頑張って実装しました。
それで提出すると、指摘を受けました。「ライブラリを使え」と。

アルゴリズムと無縁
ライブラリを使うようになってからは、アルゴリズムを強く意識して実装することがなくなりました。
仕事上のプログラミングは、サービスを開発することが求められます。
アルゴリズムの実装に時間を割くことは求められません。

今思えば、それはプログラミングに対するハードルが自分の中で下がった瞬間でもあったように思います。
「なんか難しいことが、思っていたよりも簡単に実装できる」

アルゴリズムと再開
最近、アルゴリズムを学ぶ機会がありました。
上に挙げたような、アルゴリズムやデータ構造の名前が出てきます。聞いたことはあります。
しかし、実際にそれを理解しようとすると、分からないこと、難しく感じることが多いのです。

そして少し思いました。
いろいろとプログラム書いてきたけど、理解していないところ多いなと。
自分の中の理想としては、そういったところも理解できることです。
数学の知識も多少必要となります。
正直言って難しいと感じる面があります。

ただ、そういったところも理解できるようになると、もっと自分の成果物に自信が持てるようになる気がします。
学ぶべきかと言われると、必ずしも必要とは思いません。
※ただ、試験などで求められるケースもあります
自分が学びたい、理解したいと思えたら学んでいけたら良いと思います。
もし理解することが出来たら、「理解しておくべき」と考えが変わるかもしれません。

人の拘りをただ単に受け入れること

ITエンジニアはプライドが高い集団
先日も書きましたが、ITエンジニアには拘りを持っている人が多いように思います。
エンジニアなので、職人気質なところが大いにあると思います。
それはまた、プライドが高い人が多いという意味になるかもしれません。

プライドが高い人が多く集まると、その人同士が衝突してしまうこともあります。
特に気を遣う人がその場に入ってしまうと、言いたいことがいいにくく、時には辛い思いをしてしまうかもしれません。

受け入れる
でもこれは仕方がないと受け入れてしまった方が良いと思います。
みんな価値観が違うので、何か自分と違うと感じても、それに対して都度反応しなくて良いと思います。
「ああ、そういう考え方、やり方もあるよね。」くらいで流すことが出来るといいですね。
これは自分の拘りを捨てるという意味ではありません。ただ単に受け入れるだけです。
最初はそれがストレスに感じてしまうかもしれませんが、どうせ人を変えることなんて出来ないので、自分のやるべきことに集中すれば良いと思います。

拘りに気付くと
他人の拘りに対して、一つ前向きな行動を取れるとすれば、他人の拘りに気付くことって、その人を褒めるポイントに気付くことに近いと思います。
なぜなら、拘りを認められることは、その人が認められたことになるからです。

ITエンジニア 仕事への拘り

仕事への拘り
皆さんは仕事に自分なりの拘りを持っているでしょうか。
自分の周りには、ITエンジニア(自分を含め)がたくさんいます。
彼ら(自分を含め)を少しだけ注意深く見てみると、彼らには何らかの(人によっては強い)拘りがあるように思います。

仕事の成果には人の想いがある
これはITエンジニアに限った話ではないと思いますが、仕事の成果(アウトプット)には人の想いが入っているように感じます。
ゆくゆく考えてみると当たり前のことかもしれませんね。
もしも誰もが全く同じアウトプットを出さないといけないような仕事だった場合、もしかしたらそれを面白く感じるのは難しいかもしれません。
何故ならば、それが意味するのは誰がやっても同じのように感じるからです。
※そんな中でも、ほんの少しでも良いから自分の拘りを出せると良いなと思います

その想いを受け入れること
自分が任されたから、自分がやるから、それならば自分なりの拘りや自分の色をそこに残したいと思うこと。
これはある意味、人の自然な欲求から来るものかもしれませんね。

仕事においては、それが何らかの支障をきたすこともあるかもしれません。
自分のやりたいように出来ないこともある、いや寧ろやりたいように出来ないことの方が多いと思います。
ただ、拘りを持つことそれ自体は素晴らしく、自然なことで、そのまま受け入れて良いと思います。