4

いくつかのログにメッセージを書き込むクラスがあります。このクラスは、他に何もしないユーティリティであり、バックグラウンドで実行され、いくつかのことをチェックしてログに記録します。実際に何を書いているかを気にせずに、ログが書き込まれたことを単体テストで確認できるかどうか疑問に思っています。テストされている私のクラスは次のとおりです。

//imports...

public class MyClass {
  private static Log log = LogFactory.getLog(MyClass.class);

  public MyClass() {
    log.info("MyClass is being created.");
  }

  public void doThing() {
    if( everything_is_fine ) {
      log.info("This is a message to say everything is fine.");
    } else {
      log.error("Uh oh...");
    }
  }
}

そして私のテスタークラス:

// imports ...

@RunWith(PowerMockRunner.class)
@PrepareForTest({MyClass.class,LogFactory.class})
public class MyClassTest {
  Log mockLog;

  @Before
  public void setup() {
    PowerMockito.mockStatic(LogFactory.class);
    mockLog = mock(Log.class);
    PowerMockito.when(LogFactory.getLog(MyClass.class)).thenReturn(mockLog);
  }

  @Test
  public void test_everything_is_ok() {
    MyClass mything = new MyClass();    // should write to log.info
    mything.doThing();                  // should write to log.info

    verify(mockLog, atLeastOnce()).info(anyString());
    verify(mockLog, never()).error(anyString());
  }

  @Test
  public void test_everything_is_not_ok() {
    MyClass mything = new MyClass();    // should write to log.info

    // do something which makes things not ok

    mything.doThing();                  // should write to log.error

    verify(mockLog, atLeastOnce()).info(anyString());
    verify(mockLog, atLeastOnce()).error(anyString());
  }
}

テストを実行すると、log.info() が両方のテストで呼び出され、log.error() が 2 番目のテストでのみ呼び出されることが予想されます。ただし、両方のテストの log.info で「Wanted but not invoked」が表示されます。2番目のlog.errorの場合。したがって、
1) コードが壊れていてログに書き込まれていないか、
2) テストが壊れています。

私は自分のテストで何かを台無しにしたと思っています。おそらく本当に明らかなことです。このようなものをテストした経験がある人はいますか? ありとあらゆる助けをいただければ幸いです。

アップデート:

助けてくれた人たちのおかげで、今では解決策があります。

コードを少しいじってみたところ、ログの初期化に問題があるように見えることがわかりました。モックprivate static Log log = LogFactory.getLog(MyClass.class);を正しく使用していないように見えたので、コンストラクターに移動すると、正常にモックされたように見え、すべてのテストが期待どおりに機能します。

public class MyClass {
  private static Log log;

  public MyClass() {
    MyClass.log = LogFactory.getLog(MyClass.class);
    log.info("MyClass is being created.");
  }

  // etc ...
}

今は動作していますが、最初の方法でログを初期化できなかった理由を誰か説明できますか? または、それを説明している場所を教えてください。Java がオブジェクトを初期化する方法についての私の理解にギャップがあるのか​​、それともモック フレームワークの制限なのかはわかりません。

4

2 に答える 2

0

このプロジェクトで行ったように、Logger を抽象化できます。

https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/LoggerProxy.groovy

次に、コンストラクターが必要です

https://github.com/4finance/uptodate-gradle-plugin/blob/master/src/main/groovy/com/ofg/uptodate/UptodatePlugin.groovy

1 つは LoggerProxy が初期化されたもので、もう 1 つはモックを作成して適切なテキストが渡されたかどうかを確認できるテスト用です。汚いハックは必要ありません;)

于 2014-11-20T13:03:45.763 に答える