2012-08-17 1 views
16

これは、コード単体テストロギングですか?

public class A { 

private static final Log LOG = LogFactory.getLog(A.class); 

と利用

 } catch (Exception e) { 
      LOG.error(e.getMessage(), e); 
      throw e; 
     } 

にロギング機能を確認するのが一般的だが、私はそのようなコードのためにも、単一のユニットテストを見たことがありません。

もちろん、例外と例外の例外を投げますが、ロギング情報をチェックするためのテストを書くべきですか?私は、ロギングがシステムの動作のもう一つの部分であると考える傾向があるので、テストではロギングを避けるために論理的に終了します。

私はそれをカバーしなければならないと仮定すると、模擬ログを挿入し、予期されたメッセージで「エラー」メソッドが呼び出されたことを確認するために、元のコードを変更する必要があることを意味します。しかし、元のクラスがサービスであり、それが春までにインスタンス化されている場合はどうすればよいですか?

答えて

9

ロギングライブラリをテストするのはあなた次第ではありません。しかし、例外がスローされたときに、クラスが適切なレベルでメッセージを記録することをテストすることは有益なことです。あなたがテストしているのは、コードがロギングライブラリで正しいことをすることです。

上記のコードをテスト可能にするには、依存関係注入を使用します。これは、ロガーがインタフェースILogを実装していることを前提としています。クラスターAのコンストラクターパラメーターとしてロガーを渡します。次に、テストコードはILogのモックインプリメンテーションを作成し、それをコンストラクターに渡します。上記のコードには示されていませんが、例外はどのように起こりますか。おそらく、それは他の従属オブジェクトを介している可能性があります。だから、あなたもそれを嘲笑し、例外をスローするようにしてください。その後、模擬ILogerrorメソッドを呼び出したことを確認します。おそらく、ログに記録されたメッセージを調べたいかもしれませんが、テストコードを壊れやすくすることで、あまりにも遠すぎるかもしれません。

+0

は私の質問で言及したのと同じアプローチです。しかし、私にとっては、通常はすべてのクラス用に作成されたログなので、春のサービスの場合はどうすればいいのかはっきりしていないので、クラス固有であり、シングルトンとしてはできません。 –

+0

Logオブジェクトをインスタンス化するコードを制御できない場合は、模擬ログを使用できないため、動作をテストすることは困難です。実際のLogオブジェクトでログを記録させてから、メッセージが記録されたことを確認することができます。しかし、それは自動化するのが難しいです! –

+0

いいえ、私はロギングコードをテストすることに同意しました。これは、LOGのセッターが必要なことを意味するので、テストでモックログを渡すことは可能ですが、スプリングサービスの場合はどうすればよいでしょうか。私は2つの可能な方法について考えている:1)セッターを持っているが、テストからのみ呼び出すことができる(春は自動注入を行うことができるので、そのような可視性を制限するのが難しいかもしれない)、2)ロガーを春から注入する。適切なロガーをインスタンス化します。 –

2

あなたが信頼するライブラリを呼び出すだけで何もしないテストコードをユニット化しません。
ログライブラリを信頼していますか?テストに失敗した場合は、ライブラリにバグがあるか、ライブラリを正しく設定していないためですか?構成のテストについてケアですか?

+14

ロギングライブラリがどのように動作するかはテストしていませんが、私のコードがロギングを行うことをテストすることを意図しています。 –

1

はい、ロギングが必要な処理を行っているときに、ログをテストする必要があります。たとえば、特定のイベントのログをスキャンする外部アプリケーションにフックがあります。その場合は、確実にロギングが確実に行われるようにしてください。

もちろん、すべてのログイベントをテストする必要はありません。ほとんどの場合、エラーのみ(すべてではない)をテストする必要があります。

SLF4jなどの最新のロギングフレームワークでは、メモリ内のイベントを格納し、その後にアサートできるカスタムハンドラを簡単に挿入できます。

今私の心に来て、それらの二つがあります。

SLF4JTestingは:ロギング設定の変更を必要としませんが、変更されたコードにつながる可能性があるログの工場を注入する必要があります。

SLF4J Test:slf4jtestingほど強力ではなく、開発されていないようですが、既存のコードでうまく動作します。テスト用のロガー構成以外の変更はありません。

SLF4Jテストを使用する場合、アサーションは非常に厳密で、イベント全体が等しいかどうかをチェックします。

public static Matcher<LoggingEvent> errorMessageContains(final String s) { 
    return new TypeSafeMatcher<LoggingEvent>() { 
     @Override 
     public void describeTo(final Description description) { 
      description.appendText(" type " + Level.ERROR + " should contain ") 
        .appendValue(s); 
     } 

     @Override 
     protected void describeMismatchSafely(final LoggingEvent item, final Description mismatchDescription) { 
      mismatchDescription.appendText(" was type ").appendValue(l) 
        .appendText(" message ").appendValue(item.getMessage()); 
     } 

     @Override 
     protected boolean matchesSafely(final LoggingEvent item) { 
      return item.getLevel().equals(Level.ERROR) 
        && item.getMessage().contains(s); 
     } 
    }; 
} 

これは、メッセージにテキストが含まれていることを確認しますが、それが等しいかどうかを確認することはありません。したがって、メッセージが誤植を修正したり、詳細を与えるように修正された場合、必須部分がまだ含まれていれば、テストは中断されません。

0

ロギングがビジネス要件であり、ビジネス上の価値がある場合(つまり、障害が発生した場合、問題の診断やトリアージを行う場合)、他の要件として扱う必要があります。したがって、あなたのロギングライブラリが動作することを確認するのではなく、予想される状況下でコードが必要なものを記録することを確認するために、単体テストを書くべきでしょう。このトピックに関する

より:https://ardalis.com/logging-and-monitoring-are-requirements

0

別の方法があります:あなたがたLogFactoryを模擬することができます!たとえば、

import junit.framework.Assert; 
import mockit.Mock; 
import mockit.MockUp; 
import org.apache.commons.logging.Log; 
import org.apache.commons.logging.LogFactory; 
import org.junit.Test; 

public class XXXTest { 
    class MyLog implements Log { 
     public static final String INFO = "info"; 

     private String logLevel; 
     private Object logContent; 

     public String getLogLevel() { 
      return logLevel; 
     } 

     public Object getLogContent() { 
      return logContent; 
     } 

     @Override 
     public void info(Object o) { 
      logLevel = "info"; 
      logContent = o; 
     } 

     //Implement other methods 
    } 

    @Test 
    public void testXXXFunction() { 
     final MyLog log = new MyLog(); 
     new MockUp<LogFactory>() { 
      @Mock 
      public Log getLog(String name) { 
       return log; 
      } 
     }; 

     //invoke function and log by MyLog 
     FunctionToBeTest.invoke(); 
     Assert.assertEquals("expected log text", log.getLogContent()); 
    } 
} 

幸運!

関連する問題