我们最近将 Couchbase DB 从 6.x 升级到了 7.2。其中介绍了集合和范围以及存储桶。就是这个意思
GetResult serviceInventoryJsonDocument = this.bucket.defaultCollection().get(this.getDocumentId(serviceInstanceId));
替换为
GetResult serviceInventoryJsonDocument =
bucket.scope(bucketScope).collection(bucketCollection).get(getDocumentId(serviceInstanceId));
我的存储库类是
@Primary
@Repository
public class AccessServiceInventoryRepositoryImpl extends ServiceInventoryRepositoryImpl
implements AccessServiceInventoryRepository {
private final Logger log = LoggerFactory.getLogger(getClass());
private final Gson gson = new Gson();
private static final String CALL_BUCKET_REPLACE = "We are going to call bucket.replace";
private static final String SELECT_FROM = "select * from ";
@Autowired
public AccessServiceInventoryRepositoryImpl(final ServiceInventoryMethodsValidator serviceInventoryMethodsValidator,
final CouchbaseConfigProperties couchbaseConfigProperties,
final MicroserviceConfigProperties microserviceConfigProperties,
final DomainServiceInventoryConfigProperties domainServiceInventoryConfigProperties) {
super(serviceInventoryMethodsValidator, couchbaseConfigProperties,
microserviceConfigProperties, domainServiceInventoryConfigProperties);
}
@Override
public AccessServiceInventory getServiceInventoryById(final String serviceInstanceId)
throws ServiceInventoryException {
log.debug("{} retrieving service inventory by ID {}", getClass().getSimpleName(),
getDocumentId(serviceInstanceId));
final GetResult serviceInventoryJsonDocument =
bucket.scope(bucketScope).collection(bucketCollection).get(getDocumentId(serviceInstanceId));
if (serviceInventoryJsonDocument == null) {
throw new ServiceInventoryException("No results returned, processing timeout.");
}
return gson.fromJson(serviceInventoryJsonDocument.contentAsObject().toString(), AccessServiceInventory.class);
}
}
我当前的junit测试课如下
@RunWith(MockitoJUnitRunner.class) @Ignore
public class AccessServiceInventoryRepositoryImplTest {
@Mock
private Bucket bucket;
@Mock
private Cluster cluster;
@Mock
private Collection collectionBucket;
@Mock
private GetResult getResult;
@Mock
private QueryResult queryResult;
@Mock
private QueryMetaData queryMetaData;
@Mock
private ServiceInventoryMethodsValidator serviceInventoryMethodsValidator;
private AccessServiceInventoryRepositoryImpl repositoryImpl;
@Before
public void setup() throws NoSuchFieldException, IllegalAccessException {
repositoryImpl = new AccessServiceInventoryRepositoryImpl(
serviceInventoryMethodsValidator,
CouchbaseBucketConfig.getCouchbaseConfig(), CouchbaseBucketConfig.getMicroserviceConfigProperties(),
new DomainServiceInventoryConfigProperties());
ReflectionTestUtils.setField(repositoryImpl, "cluster", cluster);
final Field bucketField = ServiceInventoryRepositoryImpl.class.getDeclaredField("bucket");
bucketField.setAccessible(true);
bucketField.set(repositoryImpl, bucket);
when(bucket.defaultCollection()).thenReturn(collectionBucket);
when(collectionBucket
.get(anyString())).thenReturn(getResult);
}
@Test(expected = ServiceInventoryException.class)
public void getServiceInventoryByIdShouldThrowServiceInventoryExceptionWhenJsonDocumentIsNull() throws Exception {
when(bucket.defaultCollection().get(anyString())).thenReturn(null);
repositoryImpl.getServiceInventoryById("123456");
}
我尝试过更改测试用例
when(bucket.defaultCollection().get(anyString())).thenReturn(null);
到
when(bucket.scope(anyString())).thenReturn(scope);
when(scope.collection(anyString())).thenReturn(collection);
when(collection.get(anyString())).thenReturn(null);
但遇到同样的异常
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class com.couchbase.client.java.Scope.
org.mockito.exceptions.base.MockitoException:
Mockito cannot mock this class: class com.couchbase.client.java.Collection
Mockito can only mock non-private & non-final classes, but the root cause of this error might be different.
我什至在 CouchbaseConfigProperties 中将集合和范围设置为非私有和非最终,但仍然遇到相同的错误 我想要这个工作
这就是为什么有些人说你应该只模拟你拥有的类型。
您可以通过改变测试方式和内容来解决这个问题。更改应用程序的设计也会有所帮助。
在某些时候,您可能需要针对真实的 Couchbase Server 集群运行测试。我强烈建议使用 TestContainers 来实现这一点。它有一个运行良好的 Couchbase 模块。
一旦您进行了与真实服务器通信的测试,您可以问自己模拟是否仍然提供价值(或者如果每次升级依赖项时模拟都会中断,那么模拟可能是一种责任)。
在应用程序设计方面,您可以围绕 Couchbase Java SDK 创建一个小包装器。您的包装器可以是一个易于模拟的接口。您无需模拟 Couchbase SDK 的类和方法,而是模拟包装器的方法。
实际上,无论如何,我都会推荐包装器方法,这样您就可以应对 Couchbase SDK API 未来可能发生的更改。一般来说,包装器还可以保护您免受后端锁定。 (免责声明:我在 Couchbase 工作。我们希望您使用 Couchbase 是因为您喜欢它,而不是因为您无力切换到其他产品。)