私が直面している問題は、同じキーでassertSameテストに失敗した2つのオブジェクトがキャッシュ可能なメソッドから返されたことです。これらのオブジェクトが同じストレージ領域を共有していないのはなぜですか?キャッシュキャッシング可能なキャッシュされたオブジェクトが等価性チェックに失敗する
詳細: 私はredisキャッシュメカニズムを使用して、スプリングブートREST APIでキャッシュを実装しています。 キャッシュは、外部から提供されたソース(データベースにアクセスするJPSリポジトリ)からデータを最初に取得し、同じキャッシュキーを後で呼び出すとキャッシュからデータを返すように正しく動作します。しかし、JUnitのテストケースでは、この動作を完全に模倣することはできません。私のassertEqualsまたはassertSameは、キャッシュから返された2つのオブジェクトで失敗します。
は私のコードベースは、以下のようになります。 MVN依存関係:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>1.7.6.RELEASE</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
Springアプリケーションの設定:
@SpringBootApplication
@EnableCaching
public class Application {
@Value("${redis.host}")
private String redisHost;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
JedisConnectionFactory jedisConnectionFactory() {
JedisConnectionFactory jedisConFactory = new JedisConnectionFactory();
jedisConFactory.setHostName(redisHost);
jedisConFactory.setPort(6379);
return jedisConFactory;
}
@Bean
public RedisTemplate<String, Object> redisTemplate() {
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
template.setConnectionFactory(jedisConnectionFactory());
return template;
}
@Bean
CacheManager cacheManager() {
return new RedisCacheManager(redisTemplate());
}
サービスクラス:
@Service
public class CIDomainService {
private RedisTemplate<String, Object> redisTemplate;
private CIDomainDAO ciDomainDAO;
@Autowired
public CIDomainService(CIDomainDAO ciDomainDAO, RedisTemplate<String, Object> redisTemplate) {
this.ciDomainDAO = ciDomainDAO;
this.redisTemplate = redisTemplate;
}
@Cacheable(value = "ciDomain", key = "#id")
public CIDomain getCIDomain(int id) {
CIDomain ciDomain = new CIDomain();
ciDomain.setId(id);
ciDomain.setName("SomeName");
return ciDomain;
}
public void clearAllCache() {
redisTemplate.delete("listCIDomains");
redisTemplate.delete("ciDomain");
}
}
上記のサービス内のciDomainDAOは、findAll()メソッドを使用して外部データベースまたはインメモリデータベースからデータを取得するJPSリポジトリインタフェースです。私のテストクラス:
@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfiles("local")
@SpringBootTest
public class CIDomainServiceIntegrationTest {
@Autowired
CIDomainService ciDomainServiceSpy;
@Before
public void setUp(){
ciDomainServiceSpy.clearAllCache();
}
@Test
public void listCIDomains_ShouldRetrieveCIDomainsWithCachingPluggedIn() {
CIDomain domain1 = ciDomainServiceSpy.getCIDomain(1);
CIDomain domain2 = ciDomainServiceSpy.getCIDomain(2);
CIDomain domain3 = ciDomainServiceSpy.getCIDomain(1);
assertSame(domain1, domain3); //fails
}
マイドメインクラス:
私は、オブジェクトが非常に最初の呼び出しのためのリポジトリから取得され、後に通話が提供キャッシュからこのオブジェクトを取得することを理解し this postに基づいて@Entity
@Table(name = "CI_DOMAIN")
public class CIDomain implements Serializable{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "name")
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
同じ「キー」が提供される。私は上記のテストケースで同じことをしていますが、assertSameは失敗しています。キャッシング可能なSpringは、指定された要求に対してフェッチされるメモリ内のオブジェクトをキャッシュしている必要があります。同じリクエストされたキーのたびに異なるオブジェクトを毎回送信するのはなぜですか?
私は、サービスクラスでスパイを使用し、同じキーリクエストに基づいてメソッド呼び出しを検証する代わりのソリューションを用意しようとしました。しかし、私はそれを行う際に別の問題に遭遇しました。サービスクラスでスパイを作成すると、キャッシュメカニズムも使用されず、同じキーが提供されていてもサービスgetCIDomainメソッドを呼び出します。私はthis、this、this、this、this、さらに詳しい分析のために多くの他の投稿を続けましたが、スパイのassertSameのどちらかを使って動作させることができませんでした。
本当にありがとうございます。
それらが同じである場合は、チェックしている( 'assertSame'(、そうではありません、彼らが必要。後者を渡すには、あなたのドメインオブジェクトに 'equals'メソッドと' hashCode'メソッドが必要です。 –
@MeDeinumあなたの返事をありがとうございます。その理由は、あなたのコメントは、シリアライズされ、デシリアライズされた "同じ"(等しいパス)のjavaオブジェクトh 2つの異なる参照またはID、したがってobject1 == object2はfalseとなります。しかし、assertSameの代わりにequalsを使用すると、「私はassertSameを使用する必要があります。そうでなければ、コードは表示されていない.equals(Object)に依存していると考えられます。すべてのプロパティを比較し、キャッシュされていない場合でもこのテストは常に成功します。 – Vishal
と同じではありません。 assertSameは 'domain1 == domain3'を実行しますが、これは別のオブジェクトインスタンスであるため、そうではありません。あなたは本当に 'equals.'を使用するべきであり、何か他のものではありません。前述したように、自分では(Redisの使用による)キャッシュはオブジェクトをシリアライズしてシリアライズするため、決して同じではありません。 java直列化を使用しても、オブジェクトは決して同じではありません。あなたが本当にオブジェクトの平等をチェックしなければならないことを信じてください。 –