2017-09-12 12 views
-1

java.time.LocalDateTimeを使用するユニットテストコードを試しています。私はモックを動かすことができますが、時間を追加すると(分または日のいずれか)、私はnullという値になります。LocalDateTime.ofが返されます。

@RunWith(PowerMockRunner.class) 
@PrepareForTest({ LocalDateTime.class }) 
public class LocalDateTimeMockTest 
{ 
    @Test 
    public void shouldCorrectlyCalculateTimeout() 
    { 
     // arrange 
     PowerMockito.mockStatic(LocalDateTime.class); 
     LocalDateTime fixedPointInTime = LocalDateTime.of(2017, 9, 11, 21, 28, 47); 
     BDDMockito.given(LocalDateTime.now()).willReturn(fixedPointInTime); 

     // act 
     LocalDateTime fixedTomorrow = LocalDateTime.now().plusDays(1); //shouldn't this have a NPE? 

     // assert 
     Assert.assertTrue(LocalDateTime.now() == fixedPointInTime); //Edit - both are Null 
     Assert.assertNotNull(fixedTomorrow); //Test fails here 
     Assert.assertEquals(12, fixedTomorrow.getDayOfMonth()); 
    } 
} 

私はLocalDateTimeは不変であること(だけでなく、私は私がそう思う)を理解し、そして私は、新しいインスタンスの代わりに、null値を取得すべきだと思うでしょう。

私にnullの値を与えているのが.ofの方法です。どうして?

+0

実行しようとしましたかモックなしのコード? powermockitoが問題を作り出している可能性があります。 – Ali

+1

最初にPowerMock(ito)を使って再考することを検討してください;-) – GhostCat

+0

Javaの「システム」クラス( 'java.time.LocalDateTime'など)を嘲笑するとき、PowerMockでは非システムクラス* '@ PrepareForTest'にリストされています(既に他の答えで指摘されているように)。しかし、私の経験では、このようなテストでの最大の間違いは、日付/タイムスタンプやシステムクロックを嘲笑するという考えを楽しませることさえあります。 SUTが 'LocalDateTime.now()'を使用している場合は、日付オブジェクトを(呼び出し側コードによって)外部から与えることが可能でなければなりません。そこに行って、それをしてください。 –

答えて

4

使用PowerMock.mockStatic(ClassThatContainsStaticMethod.class)、このクラスのすべて方法を模擬します。

と:あなたはクラスが最終であっても、クラスの静的メソッドを模擬することができます

注意。この方法は最終的なものでもよい。 クラスの特定の静的メソッドのみをモックするには、partial mockingセクションのマニュアルを参照してください。

システムクラスで静的メソッドをモックするには、thisの方法に従う必要があります。

あなたはすべての静的メソッドをモックするように指示しましたが、of()メソッドのモックは供給しませんでした。

解決策:of()メソッドのモックを追加するか、部分的なモックを使用するように変更すると、of()メソッドはモックされません。

基本的にの説明書を読んで、指示に従ってください。

1

したがって、PowerMockito.mockStaticは次のコード行を使いこなしていました。単にmockStaticの前に実行するfixedPointInTimeのインスタンス化を移動するだけで、すべての作業が可能になります。 documentationによると

4

@Andreas' answerは、PowerMockの使い方について正しく説明しています(また、あなたはin your own answerを見つけました)。

私は別のアプローチを追加したいと思います。現在の日付/時刻をテストするには、java.time.Clockを使用します。このクラスを使用すると、fixed clockClockは常に同じ現在の日付/時刻を返します)とuse it in your testを作成できます。

これで、静的メソッドをモックする必要はありません(PowerMockアノテーションをテストクラスから削除する必要がありました)。すべてのインスタンスが対応しますが、

@Test 
public void shouldCorrectlyCalculateTimeout() { 
    // create a clock that always returns the same current date/time 
    LocalDateTime fixedPointInTime = LocalDateTime.of(2017, 9, 11, 21, 28, 47); 
    ZoneId zone = ZoneId.systemDefault(); 
    Clock clock = Clock.fixed(fixedPointInTime.atZone(zone).toInstant(), zone); 

    // use the clock in now() method 
    LocalDateTime fixedTomorrow = LocalDateTime.now(clock).plusDays(1); 

    // assert (use equals() instead of == because it doesn't return the same instance) 
    Assert.assertTrue(LocalDateTime.now(clock).equals(fixedPointInTime)); 
    Assert.assertNotNull(fixedTomorrow); 
    Assert.assertEquals(12, fixedTomorrow.getDayOfMonth()); 
} 

私はnow(clock)の新しいインスタンスを作成しますので、日付を比較する(代わりに==の)equals()メソッドを使用する必要がありました:唯一の違いは、クロックがnow()メソッドに渡さなければならないということです同じ日付/時間(それは重要なことですが、IMO)。


PS:私は上記のコードではJVMのデフォルトのタイムゾーン(ZoneId.systemDefault())を使用しています。唯一の問題はそれがcan be changed without notice, even at runtimeだから、あなたが使っているものを常に明示的にする方が良いです。

この特定のコードでは、タイムゾーン部分が無視されているため、ゾーンを使用することはできません。これは大きな違いはありません。夏時間の切り替えが発生した場合は、予期しない結果が生じる可能性があります。

これに頼らない場合は、代わりにZoneId.systemDefault()を置き換えてZoneOffset.UTCを使用してください(UTCには夏時間効果がありません)。テストケースで

@PrepareForTest(SomeClass.class) 

@RunWith(PowerMockRunner.class) 

public class SomeClass{ 

    public static void main(String[] args) { 
     LocalDateTime now = getCurrentLocalDateTime(); 
     System.out.println(now); 
    } 

    private LocalDateTime getCurrentLocalDateTime() { 
     return LocalDateTime.now(); 
    } 

} 

そして、あなたが使用Testクラスのように、あなたのクラスのメソッドを作成します

ZoneOffset utc = ZoneOffset.UTC; 
Clock clock = Clock.fixed(fixedPointInTime.toInstant(utc), utc); 
0

:この場合、あなたはこのようなあなたの時計を作成することができます:

LocalDateTime tommorow= LocalDateTime.now().plusDays(1); 

SomeClass classUnderTest = PowerMockito.spy(new SomeClass()); 

PowerMockito.when(classUnderTest, "getCurrentLocalDateTime").thenReturn(tommorow); 
関連する問題