4

のデフォルトコンストラクターをモックしたいjava.util.dateので、作成された時刻を表すオブジェクトを作成しませんDateが、常に同じDateオブジェクトを作成します(私の例では2010年12月31日以下)。JMockitとでこれを試してみましJUnitたが、以下のテストを実行すると、出力は常にThu Jan 01 01:00:00 CET 1970です。それで、私のモックの何が問題になっていDate()ますか?

import java.util.Date;

import org.junit.*;
import mockit.*;

public class AppTest {

    @Before
    public void setUp() {
        Mockit.setUpMocks(MockedDate.class);
    }

    @After
    public void tearDown() {
        Mockit.tearDownMocks();
    }  

   @Test
    public void testDate() {
        Date today=new Date();
        System.out.println(today.toString());
    }

    @MockClass(realClass=Date.class)
    public static class MockedDate {

        @Mock
        public void $init() {
            // Now should be always 31.12.2010!
            new Date(110,11,31);  //110 = 2010! 11 = December! This is sick!
        }
    }
}
4

4 に答える 4

11

アルニックの答えは私にとって良いヒントでした。偽の時間を生成するSystemには、クラスではなくクラスをモックすることをお勧めします。Date結局のところ、私自身の解決策は、単にメソッドをモックすることでしたSystem.currentTimeMillis()(このメソッドはDate()内部で呼び出されます)。

JMockit1.5以降

new MockUp<System>(){

    @Mock
    public long currentTimeMillis() {

        // Now is always 11/11/2011
        Date fake = new Date(111,10,11);
        return fake.getTime();
    }
};

JMockit1.4以前

@MockClass(realClass = System.class)
public static class MockedSystem {

    @Mock
    public long currentTimeMillis() {

        // Now is always 11/11/2011
        Date fake = new Date(111,10,11);
        return fake.getTime();
    }
}
于 2010-12-31T09:33:14.827 に答える
9

テスト駆動の本で示唆されているように、JavaクラスでSystemTime抽象化を使用することをお勧めします。メソッド呼び出し(System#currentTimeMillisおよびCalendar#getInstance)と直接構築(new Date())を次のような静的メソッド呼び出しに置き換えます。

long time = SystemTime.asMillis();
Calendar calendar = SystemTime.asCalendar();
Date date = SystemTime.asDate();

時間を偽造するには、SystemTimeクラスによって返されるものを変更する必要があります。
SystemTimeは、デフォルトでSystem.currentTimeMillis()に委任するTimeSourceインターフェイスを使用します

public interface TimeSource {
    long millis();
}

構成可能なSystemTime実装は、次のようになります。

public class SystemTime {
    private static final TimeSource defaultSrc =
            new TimeSource() {
                public long millis() {
                    return System.currentTimeMillis();
                }
            };

    private static TimeSource source = null;
    public static long asMillis() {
        return getTimeSource().millis();
    }

    public static Date asDate() {
        return new Date(asMillis());
    }
    public static void reset() {
        setTimeSource(null);
    }
    public static void setTimeSource(TimeSource source) {
        SystemTime.source = source;
    }
    private static TimeSource getTimeSource() {
        return (source != null ? source : defaultSrc);
    }
}

そして、あなたが単にする戻り時間を偽造するために

@Test
public void clockReturnsFakedTimeInMilliseconds() throws Exception {
    final long fakeTime = 123456790L;
    SystemTime.setTimeSource(new TimeSource() {
        public long millis() {
                return fakeTime;
        }
    });
    long clock = SystemTime.asMillis();
    assertEquals("Should return fake time", fakeTime, clock);
}

Joda-Timeライブラリは、Javaでの日付の操作を簡素化し、箱から出してこのようなものを提供します

于 2010-12-30T16:20:09.583 に答える
0

あなたはコンストラクターを嘲笑し、その中でDateのインスタンス(構築されたものとは何の関係もありません)を作成し、それを捨てました。デフォルトのコンストラクターがモックアウトされているため、日付は現在の時刻に初期化されないため、時刻はゼロになります(1970-01-01を表します)。

返された日付を変更するには、次のように魔法の「it」属性を使用する必要があります。

@MockClass(realClass=Date.class)
public static class MockedDate {

    public Date it;
    @Mock
    public void $init() {
        // This is sick!
        it.setDate(31);
        it.setYear(110); // 110 = 2010!
        it.setMonth(11); // 11 = December!
    }
}
于 2010-12-30T15:24:54.857 に答える
0

そして、@asmaierのすばらしい答えに基づいた完全なJUnitの例を次に示します。

    @Test
    public void dateConstructorReturnsMockedDate() throws ParseException {
        final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
        final Date mockDate = dateFormat.parse("2002-02-02");

        new MockUp<System>(){
            @Mock
            public long currentTimeMillis() {
                return mockDate.getTime();
            }
        };

        final Date actualDate = new Date();
        assertThat(actualDate).isEqualTo(mockDate); // using AssertJ
    }

Mavenを使用する場合は、次のようにJMockitを構成しますpom.xml

    <dependencies>
        <dependency>
            <groupId>org.jmockit</groupId>
            <artifactId>jmockit</artifactId>
            <version>${jmockit.version}</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>${maven-surefire-plugin.version}</version>
                <configuration>
                    <argLine>
                        -javaagent:${settings.localRepository}/org/jmockit/jmockit/${jmockit.version}/jmockit-${jmockit.version}.jar
                    </argLine>
                    <disableXmlReport>true</disableXmlReport>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <properties>
        <jmockit.version>1.44</jmockit.version>
    </properties>
于 2020-09-08T10:04:40.553 に答える