51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

尝试使我的简单缓存通过所有单元测试,但在其中一个测试上仍然失败。

英文:

Trying to get my simple aged cache to pass all unit tests, keeps failing on one of them

问题 {#heading}

简单的年龄缓存:
我创建了一个简单的年龄缓存,并且已经使它通过了所有的单元测试,除了getExpired。我尝试在put之后和之前运行cleanExpiredRecords方法,但真的不知道该如何修复这个问题。任何建议将不胜感激。

package io.collective;

import java.time.Clock;
import java.util.HashMap;
import java.util.Map;

public class SimpleAgedCache {
    private final Clock clock;
    private final Map<Object, CacheEntry> cacheMap;

    public SimpleAgedCache(Clock clock) {
        this.clock = clock;
        this.cacheMap = new HashMap<>();
    }

    public SimpleAgedCache() {
        this(Clock.system(Clock.systemDefaultZone().getZone()));
    }

    public void put(Object key, Object value, int retentionInMillis) {
        if (key != null && retentionInMillis > 0) {
            long expirationTime = clock.millis() + retentionInMillis;
            cacheMap.put(key, new CacheEntry(value, expirationTime));
        }
    }

    public boolean isEmpty() {
        return cacheMap.isEmpty();
    }

    public int size() {
        return cacheMap.size();
    }

    public Object get(Object key) {
        cleanExpiredRecords();
        CacheEntry entry = cacheMap.get(key);
        if (entry != null) {
            return entry.value;
        }
        return null;
    }

    private void cleanExpiredRecords() {
        long currentTime = clock.millis();
        cacheMap.entrySet().removeIf(entry -> entry.getValue().isExpired(currentTime));
    }

    private static class CacheEntry {
        Object value;
        long expirationTime;

        CacheEntry(Object value, long expirationTime) {
            this.value = value;
            this.expirationTime = expirationTime;
        }

        boolean isExpired(long currentTime) {
            return currentTime >= expirationTime;
        }

        boolean isNotExpired(long currentTime) {
            return !isExpired(currentTime);
        }
    }
}

它一直失败的JUnit测试如下。我试图让我的代码通过单元测试。但是,它一直返回2,而期望的答案是1。
期望:1
实际:2

@Test
public void getExpired() {
    TestClock clock = new TestClock();

    SimpleAgedCache expired = new SimpleAgedCache(clock);
    expired.put("aKey", "aValue", 2000);
    expired.put("anotherKey", "anotherValue", 4000);

    clock.offset(Duration.ofMillis(3000));

    assertEquals(1, expired.size());
    assertEquals("anotherValue", expired.get("anotherKey"));
}

英文:

Simple Aged Cache:
I have created a simple aged cache and I have got it to pass all unit tests except getExpired. I have tried running the cleanExpiredRecords method after the put, and before, really not sure how to fix this. Any suggestions would be appreciated.

package io.collective;
import java.time.Clock;
import java.util.HashMap;
import java.util.Map;
public class SimpleAgedCache {
private final Clock clock;
private final Map&lt;Object, CacheEntry&gt; cacheMap;
public SimpleAgedCache(Clock clock) {
this.clock = clock;
this.cacheMap = new HashMap&lt;&gt;();
}
public SimpleAgedCache() {
this(Clock.system(Clock.systemDefaultZone().getZone()));
}
public void put(Object key, Object value, int retentionInMillis) {
if (key != null &amp;&amp; retentionInMillis &gt; 0){
long expirationTime = clock.millis() + retentionInMillis;
cacheMap.put(key, new CacheEntry(value, expirationTime));
}
}
public boolean isEmpty() {
return cacheMap.isEmpty();
}
public int size() {
return cacheMap.size();
}
public Object get(Object key) {
cleanExpiredRecords();
CacheEntry entry = cacheMap.get(key);
if (entry != null){
return entry.value;
}
return null;
}
private void cleanExpiredRecords(){
long currentTime = clock.millis();
cacheMap.entrySet().removeIf(entry -&gt; entry.getValue().isExpired(currentTime));
}
private static class CacheEntry{
Object value;
long expirationTime;
CacheEntry(Object value, long expirationTime){
this.value = value;
this.expirationTime = expirationTime;
}
boolean isExpired(long currentTime){
return currentTime &gt;= expirationTime;
}
boolean isNotExpired(long currentTime){
return !isExpired(currentTime);
}
}
}

The Junit test that it keeps failing is below. I am trying to get my code to pass the unit test. However, it keeps returning 2 when the expected answer is 1.
Expected :1
Actual :2

@Test
public void getExpired() {
TestClock clock = new TestClock();
SimpleAgedCache expired = new SimpleAgedCache(clock);
expired.put(&quot;aKey&quot;, &quot;aValue&quot;, 2000);
expired.put(&quot;anotherKey&quot;, &quot;anotherValue&quot;, 4000);
clock.offset(Duration.ofMillis(3000));
assertEquals(1, expired.size());
assertEquals(&quot;anotherValue&quot;, expired.get(&quot;anotherKey&quot;));
}

答案1 {#1}

得分: 1

我不看到在两个 "puts" 和 "size-call" 之间会删除元素。 英文:

I don't see that elements will be removed between the two puts and the size-call.

答案2 {#2}

得分: 1

你的清理方法在客户端调用get()时触发,但在调用size()时不会触发。换句话说,当你调用size()时,你的缓存实际上包含了两个键值对,并且仅在调用get()时才删除过期的记录。

这不应该失败:

@Test
public void getExpired() {
    TestClock clock = new TestClock();

    SimpleAgedCache expired = new SimpleAgedCache(clock);
    expired.put("aKey", "aValue", 2000);
    expired.put("anotherKey", "anotherValue", 4000);

    clock.offset(Duration.ofMillis(3000));

    assertEquals("anotherValue", expired.get("anotherKey"));
    assertEquals(1, expired.size());
}

英文:

Your cleanup method is triggered when the client calls get(), but not when it calls size(). In other words, when you call size(), your cache actually holds two key -> value pairs, and the expired record is removed only when you call get().

This should not fail:

@Test
public void getExpired() {
TestClock clock = new TestClock();
SimpleAgedCache expired = new SimpleAgedCache(clock);
expired.put(&quot;aKey&quot;, &quot;aValue&quot;, 2000);
expired.put(&quot;anotherKey&quot;, &quot;anotherValue&quot;, 4000);
clock.offset(Duration.ofMillis(3000));
assertEquals(&quot;anotherValue&quot;, expired.get(&quot;anotherKey&quot;));
assertEquals(1, expired.size());
}

赞(0)
未经允许不得转载:工具盒子 » 尝试使我的简单缓存通过所有单元测试,但在其中一个测试上仍然失败。