Mockitoでprivateメソッドのテストっぽいこと

ReflectionTestUtilsを使用する

fieldの場合

ReflectionTestUtils.setField を使う

public Sample SampleRepositoryImpl{
    private String parameter;
}


@Runwith(SpringRunner.class)
class SampleRepositoryImplTest(){

            @InjectMocks
            private SampleRepositoryImpl sampleRepository

            @Before
            public void setUp(){
                    ReflectionTestUtils.setField(sampleRepository,"parameter","local");
            }
}

上記のような感じで、差し替えができる。とても簡単。staticフィールドもできるもよう。

methodの場合

private methodをテストしたいときは、これで結果が取れるので、Assertiosでチェックしてやればいい。

ReflectionTestUtils.invokeMethod を使う

public Sample SampleRepositoryImpl{
        private Sring sampleMethod(){
             return "sample";
        }
}


@Runwith(SpringRunner.class)
class SampleRepositoryImplTest(){

            @InjectMocks
            private SampleRepositoryImpl sampleRepository

            @Test
            public void privateMethodTest(){
                    ReflectionTestUtils.invokeMethod(sampleRepository,"sampleMethod", null);
            }
}

staticメソッドもできるもよう。

まとめ

MockitoでprivateメソッドでテストするのはできなくてPowerMock使えって書いてあるけど、バージョンとか意識しないといけないの面倒だから、Mockitoでできないかなって調べたら、このくらいのことはできるので、わざわざライブラリ追加しなくていいかなって感じでした。

nginxのupstreamのnameは_-とか使えない

ちょっとした社内向けのマイクロサービスしてると1つのnginxでいろんなところに飛ばす必要がでてきてしまい…
スネークケースとかケバブケースでnginx.confを書こうとしたらエラーになったのでメモ


upstream app_lb { server app.local }

この設定はNG

upstream applb {
     server app.local 
}

こっちはOK

nginxの設定のキー名によく_がでてくるから使えるかと思ったら使えなかった
ざざざっと書いたあとでエラーになったので、あせる

ちなみにエラーにはなるのだが、定義されてないので、使えないっていうのがさらに時間を溶かしていった

ログインシェルの変更

jenkinsなどで使いたいときがあるので、メモ

$ sudo chsh jenkins

これで使いたいshellを入れればOK

docker-credential-ecr-loginのインストール

docker-credential-ecr-login を使えば、楽だよってでてたので、インストール

(golang 入ってない人は yum | brew | apt-get でインストールする)

$ go get -u github.com/awslabs/amazon-ecr-credential-helper/ecr-login/cli/docker-credential-ecr-login

これでインストールおわり。

aws configureでaccess keyと secret access keyを設定する

$ aws configure --profile ecr 
AWS Access Key ID [**********************]: 
AWS Secret Access Key [**********************]: 
Default region name [ap-northeast-1]: 
Default output format [json]: 

ECRのログイン情報する

$ aws ecr get-login --no-include-email --region ap-northeast-1
docker login -u AWS -p ${long password}  https://${repository number}.dkr.ecr.ap-northeast-1.amazonaws.com

ログインコマンドが発行されるので、これを実行する

$ docker login -u AWS -p ${long password}  https://${repository number}.dkr.ecr.ap-northeast-1.amazonaws.com

WARNING! Using --password via the CLI is insecure. Use --password-stdin.
error getting credentials - err: exec: "docker-credential-ecr-login": executable file not found in $PATH, out: ``

変なエラーがでる。。。
とおもったら、 docker-credential-ecr-login にパスが通ってないもよう。

パスを通して再度実行して解決

$ vi ~/.bash_profile

export PATH=$PATH:~/go/bin  <- これを追加

このエラーの対応方法 org.im4java.core.CommandException: convert: no decode delegate for this image format

macでim4javaを使おうとしたらこんなエラーが

org.im4java.core.CommandException: convert: no decode delegate for this image format `' @ error/constitute.c/ReadImage/509.

どうやらコーデックに対応していないとのこと。
Linuxでの対応サイトでは、ソースからインストールすればいいとのことなので、brewでもそれをやる

$ brew remove imagemagick
$ brew install imagemagick --build-from-source

コンパイルに時間はかかるけど、これでいけます。

Spring Webfluxでのinterceptorメモ

Spring WebfluxはServlet使えないのでInterceptorとかないらしい。

Spring WebfluxではWebFilterを使うらしいので、メモ。


import lombok.extern.slf4j.Slf4j; import org.springframework.context.annotation.Configuration; import org.springframework.security.core.context.SecurityContext; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.WebFilter; import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebSession; import reactor.core.publisher.Mono; @Configuration @Component @Slf4j public class SampleWebFilter implements WebFilter { @Override public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) { return chain.filter(exchange) .doOnRequest(value -> onRequest(exchange)) .doOnSuccess(done -> onSuccess()) .doOnSuccessOrError((success, error) -> onSuccessOrError()); } // controller前に呼ばれる private void onRequest(ServerWebExchange exchange) { log.info("{}", exchange); Mono<WebSession> session = exchange.getSession(); log.info("{}", session); SecurityContext context = SecurityContextHolder.getContext(); log.info("{}", context); log.info("onRequest"); } // exception発生しないときに呼ばれる private void onSuccess() { log.info("onSuccess"); } // exception発生しないときに呼ばれる private void onError() { log.info("onError"); } // 成功でもエラーでも呼ばれる private void onSuccessOrError() { log.info("onSuccessOrError"); } }

リクエストの中身もとれるのだが、thread localを使わないほうがいいらしいので、そこで処理したものはどうしたらいいんだろ…

doOnEach()doOnSuccessOrError() の違いはまだわかってないw

Spring5 Reactive(webflux)での@validのBindingResultの書き方かわってたのでメモ

もしかしたらwebflux関係ないかもだけど、Spring5 Reactive触ってたら、(@valid Form form , BindingResult bindingResult) こんなのが動かなくて調べたらメソッドとして独立するようになっていた

こんな感じ。
modelも引数にとれるので、viewを使ってるときは、これで対応可能。

@ExceptionHandler(WebExchangeBindException.class)
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    public Object handleException(WebExchangeBindException errors, Model model){
        Response response = new Response();
        response.setErrors(errors.getBindingResult());
        return response;
    }

SpringBoot2.0で There is no PasswordEncoder mapped for the id “null” エラーが…

SpringBoot2.0でいろいろ試してたら、 起動時にThere is no PasswordEncoder mapped for the id "null"のエラーがでてた。
どうやら、passwordencoder設定されてないとでるらしい。

DeprecatedだがNoOpPasswordEncoderというのがあるので、こちらをセットしたら起動できた。

@Configuration
@EnableWebSecurity
@ComponentScan
public class WebSecruityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/login").permitAll()
                .anyRequest().access("isAuthenticated()")
                .and()
                .formLogin()
                .and()
                .rememberMe();

    }


    public void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.inMemoryAuthentication()
                .withUser("hoge")
                .password("fuga")
                .authorities(Collections.emptyList());

    }

    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }

}

新しく言語を習得するときにロゼッタコード(rosettacode)を参考にする

タイトルの通りだが、新しく言語を習得するときは、チュートリアルもそうなんだが、結構rosettacodeで逆引きして、へぇーこーゆー風に書くんだーみたいなのをみてみたりする

ロゼッタコード

タスクを選ぶ

もちろん英語サイトなので、アレルギーがある人には見た瞬間「うっ」ってなるかもですけど、中身は簡単
下記のページで参考にしてみたいタスクをクリックし、言語ごとに実装例がかいてあるので、それを参考にする
http://www.rosettacode.org/wiki/Category:Programming_Tasks

fizzbuzz

例えばみんなだいすきfizzbuzzとかもある
http://www.rosettacode.org/wiki/FizzBuzz

Nimで書くとこんな感じ

for i in 1..100:
  if i mod 15 == 0:
    echo("FizzBuzz")
  elif i mod 3 == 0:
    echo("Fizz")
  elif i mod 5 == 0:
    echo("Buzz")
  else:
    echo(i)

Swiftで書くとこんな感じ

for i in 1...100 {
    switch (i % 3, i % 5) {
    case (0, 0):
        print("FizzBuzz")
    case (0, _):
        print("Fizz")
    case (_, 0):
        print("Buzz")
    default:
        print(i)
    }
}

Luaで書くとこんな感じ

word = {"Fizz", "Buzz", "FizzBuzz"}

for i = 1, 100 do
        print(word[(i % 3 == 0 and 1 or 0) + (i % 5 == 0 and 2 or 0)] or i)
end

Adaで書くとこんな感じ

with Ada.Text_IO; use Ada.Text_IO;

procedure Fizzbuzz is
begin
   for I in 1..100 loop
      if I mod 15 = 0 then
         Put_Line("FizzBuzz");
      elsif I mod 5 = 0 then
         Put_Line("Buzz");
      elsif I mod 3 = 0 then
         Put_Line("Fizz");
      else
         Put_Line(Integer'Image(I));
      end if;
   end loop;
end Fizzbuzz;

まぁこのように結構な言語数がある。実際にこのコードがベスト・プラクティスなわけではないが、参考にはなる。

sha-256

nimでsha-256でハッシュしたいときに、さっと見られるので、便利

import strutils

const SHA256Len = 32

proc SHA256(d: cstring, n: culong, md: cstring = nil): cstring {.cdecl, dynlib: "libssl.so", importc.}

proc SHA256(s: string): string =
  result = ""
  let s = SHA256(s.cstring, s.len.culong)
  for i in 0 .. < SHA256Len:
    result.add s[i].BiggestInt.toHex(2).toLower

echo SHA256("Rosetta code")

まか書き方が冗長だったりすることもあるかもだが、それは自分で直せばいいし、あくまで参考程度にみるには結構重宝するサイトだと思う

ライブチャットサービスのlivezillaを入れてみた

ライブチャットサービスでいいのないかなーって探してたらオンプレでできそうないいものがあったので、メモ

サイトに来てもらって、そこからのコンバージョンを上げたいとかあるんだけど、ユーザが何思ってるかとか組み上げるものがあんまりなかったので、導入したいなーと思ってSaaSのものをみてたんだけど、月額安いんだけど、オペレータ増やすと途端に値段あがってくし、ログあんまり残らないし、性能でるかわからんしってことで、オンプレでできるのを探しており、Livezillaっていうのを見つけた。

LiveZilla概要

  • 構成はPHP + JS + MySQLという感じで超シンプル。
  • ソースコードはやや見づらいがメンテできないほどではない
  • オペレータは1名だけなら永久無料(30日間は無制限利用)
  • オペレータのクライアントアプリがある
    • デスクトップ(win,linux,mac)
    • モバイル(iOS, Android)
  • 翻訳機能(エディタ)がある

  • ボット用のAPIがある
  • オペレータ画面でユーザが表示してる画面がみえる(入力までは見えない)
  • チケット管理ができる
  • ブラックリスト管理
  • 優先順位管理
  • slack連携できる
    などなど、もう機能としては十分である。

画面はこんな感じ

ライセンス

あと、ライセンスが買い切りで無制限プランが999ユーロらしく、結構やすい。
zopimとかのだと3オペレータ10ヶ月分で10万弱なので、ならボット無制限でつくれるので、いいかなと。

ビジネスとしては

アップデートライセンスは別にある。これは予測だけど、クライアントアプリ(デスクトップ、スマホとも)は多分、最新のLiveZillaのAPIにしか対応してないとかなんとかで、そのアップデートライセンスを買わせるモデルなんじゃないかなと。ただ、アップデートライセンスもそれほど高くなく、499ユーロくらいなので、別に全然いい。

さて、これでコンバージョンあがるといいなー。