C# 使用Moq的ElasticClient代码覆盖率
我试图通过单元测试来分析代码覆盖率,我目前正在使用Moq库来执行单元测试,不知何故,我进入了一条错误的道路,我想知道下面的场景是否适用于使用Moq 下面是一段代码C# 使用Moq的ElasticClient代码覆盖率,c#,unit-testing,
elasticsearch,moq,code-coverage,C#,Unit Testing,
elasticsearch,Moq,Code Coverage,我试图通过单元测试来分析代码覆盖率,我目前正在使用Moq库来执行单元测试,不知何故,我进入了一条错误的道路,我想知道下面的场景是否适用于使用Moq 下面是一段代码 public interface ISearchWorker { void DeleteIndex(string indexName); T GetClient<T>(); } public class ElasticSearchWorker : ISearchWorker { public v
public interface ISearchWorker
{
void DeleteIndex(string indexName);
T GetClient<T>();
}
public class ElasticSearchWorker : ISearchWorker
{
public void DeleteIndex(string indexName)
{
IElasticClient elasticClient = GetClient<IElasticClient>();
if (elasticClient.IndexExists(indexName).Exists)
{
_ = elasticClient.DeleteIndex(indexName);
}
}
public T GetClient<T>()
{
string nodeList = "http://localhost:9200/";
List<Node> nodes = nodeList.Split(',').Select(uri => new Node(new Uri(uri))).ToList();
IConnectionPool sniffingConnectionPool = new SniffingConnectionPool(nodes);
IConnectionSettingsValues connectionSettings = new ConnectionSettings(sniffingConnectionPool);
return (T)(IElasticClient)new ElasticClient(connectionSettings);
}
}
公共接口ISearchWorker
{
void DeleteIndex(字符串索引名);
T GetClient();
}
公共类ElasticSearchWorker:ISearchWorker
{
公共void DeleteIndex(字符串索引名)
{
IElasticClient elasticClient=GetClient();
if(elasticClient.indexists(indexName.Exists)
{
_=elasticClient.DeleteIndex(indexName);
}
}
公共T GetClient()
{
字符串节点列表=”http://localhost:9200/";
List nodes=nodeList.Split(',')。选择(uri=>newnode(newuri(uri))).ToList();
IConnectionPool sniffingConnectionPool=新的sniffingConnectionPool(节点);
IConnectionSettingsValuesConnectionSettings=新连接设置(嗅探连接池);
返回(T)(IElasticClient)新ElasticClient(连接设置);
}
}
下面是单元测试的代码片段
[TestClass]
public class SearchTestClass
{
private ISearchWorker searchWorker;
private Mock<ISearchWorker> searchWorkerMoq;
private readonly string indexName = "testIndex";
[TestInitialize]
public void SetupElasticClient()
{
searchWorkerMoq = new Mock<ISearchWorker>();
var elasticClient = new Mock<IElasticClient>();
searchWorkerMoq.Setup(c => c.GetClient<IElasticClient>()).Returns(elasticClient.Object).Verifiable();
searchWorker = searchWorkerMoq.Object;
}
[TestMethod]
public void DeleteIndexTest()
{
try
{
searchWorker.DeleteIndex(indexName);
searchWorkerMoq.Verify(c => c.GetClient<IElasticClient>(), Times.Once());
}
catch (System.Exception)
{
throw;
}
}
}
[测试类]
公共类SearchTestClass
{
私人搜索工作者;
私有模拟searchWorkerMoq;
私有只读字符串indexName=“testIndex”;
[测试初始化]
public void SetupElasticClient()
{
searchWorkerMoq=newmock();
var elasticClient=new Mock();
searchWorkerMoq.Setup(c=>c.GetClient()).Returns(elasticClient.Object).Verifiable();
searchWorker=searchWorkerMoq.Object;
}
[测试方法]
public void DeleteIndexTest()
{
尝试
{
searchWorker.DeleteIndex(indexName);
searchWorkerMoq.Verify(c=>c.GetClient(),Times.Once());
}
捕获(系统异常)
{
投掷;
}
}
}
线路
searchWorkerMoq.Verify(c => c.GetClient<IElasticClient>(), Times.Once());
searchWorkerMoq.Verify(c=>c.GetClient(),Times.Once());
引发以下异常
(Moq.MockException: '
Expected invocation on the mock once, but was 0 times: c => c.GetClient<IElasticClient>())
(Moq.MockException:'
应在模拟上调用一次,但调用次数为0次:c=>c.GetClient()
通过阅读大多数Moq相关信息,似乎这不是执行Moq测试的适当方式,应在ElasticSearchWorker类外部提供IElasticClient对象
不从外部注入提供IElasticClient对象的原因是,我们计划为另一个搜索提供程序(Azure search)实现ISearchWorker,因此希望将客户端实体封装在实现ISearchWorker接口的类中
想知道是否有更好的方法来执行此测试,以及我们如何实现此场景的代码覆盖率。因此我假设您理解为什么这不起作用,并且您只是要求“一个好方法”来修复此问题 现在我并不是说这是最好的方法,但在保持“干净”的同时,这可能是最快的方法 应用界面分离(“I”与固体)。制作两个接口,而不是一个,然后在稍后阶段实现这两个接口
// Don't have a C# IDE with me, so sorry if I leave some syntax errors.
public interface ISearchClientProvider
{
T GetClient<T>();
}
public interface ISearchWorker
{
void DeleteIndex(string indexName);
}
public class ElasticSearchWorker : ISearchWorker{
private readonly ISearchClientProvider _clientProvider;
public ElasticSearchWorker(ISearchClientProvider clientProvider){
_clientProvider = clientProvider;
}
public void DeleteIndex(string indexName)
{
var elasticClient = _clientProvider.GetClient<IElasticClient>();
if (elasticClient.IndexExists(indexName).Exists)
{
_ = elasticClient.DeleteIndex(indexName);
}
}
}
public class ElasticSearchClientProvider : ISearchClientProvider{/*some implementation*/}
public class AzureSearchWorker : ISearchWorker{/*some implementation*/}
public class AzureSearchClientProvider : ISearchClientProvider{/*some implementation*/}
//我身上没有C#IDE,如果我留下一些语法错误,那么很抱歉。
公共接口ISearchClientProvider
{
T GetClient();
}
公共接口ISearchWorker
{
void DeleteIndex(字符串索引名);
}
公共类ElasticSearchWorker:ISearchWorker{
私有只读ISearchClientProvider\u clientProvider;
公共ElasticSearchWorker(ISearchClientProvider clientProvider){
_clientProvider=clientProvider;
}
公共void DeleteIndex(字符串索引名)
{
var elasticClient=_clientProvider.GetClient();
if(elasticClient.indexists(indexName.Exists)
{
_=elasticClient.DeleteIndex(indexName);
}
}
}
公共类ElasticSearchClientProvider:ISearchClientProvider{/*某些实现*/}
公共类AzureSearchWorker:ISearchWorker{/*一些实现*/}
公共类AzureSearchClientProvider:ISearchClientProvider{/*某些实现*/}
那么测试代码应该是这样的:
// would actually prefer to name it ElasticSearchWorkerTests
[TestClass]
public class SearchTestClass
{
private readonly ElasticSearchWorker _searchWorker;
private readonly ISearchClientProvider _elasticClientProvider;
private readonly string indexName = "testIndex";
// would prefer to name it SetupElasticSearchWorker
[TestInitialize]
public void SetupElasticClient()
{
var elasticClient = new Mock<IElasticClient>();
// Setup for IElasticClient.IndexExists() function:
// I don't know what is the return type of IndexExists,
// so I am assuming here that it is some dynamic Object
elasticClient.Setup(c => c.IndexExists(indexName)).Returns(new {Exists = true});
// Setup for IElasticCleint.DeleteIndex might also be necessary here.
_elasticClientProvider = new Mock<ISearchClientProvider>();
_elasticClientProvider.Setup(c => c.GetClient<IElasticClient>()).Returns(elasticClient.Object).Verifiable();
_searchWorker = new ElasticSearchWorker(_elasticClientProvider);
}
// would prefer to name it DeleteIndexTest_GetsSearchClient,
// because the function does more than is checked here, e.g., Checks index, deletes index.
[TestMethod]
public void DeleteIndexTest()
{
try
{
searchWorker.DeleteIndex(indexName);
searchWorkerMoq.Verify(c => c.GetClient<IElasticClient>(), Times.Once());
}
catch (System.Exception)
{
throw;
}
}
}
//实际上更愿意将其命名为ElasticSearchWorkerTests
[测试类]
公共类SearchTestClass
{
私有只读ElasticSearchWorker\u searchWorker;
私有只读ISearchClientProvider\u elasticClientProvider;
私有只读字符串indexName=“testIndex”;
//更愿意将其命名为SetupElasticSearchWorker
[测试初始化]
public void SetupElasticClient()
{
var elasticClient=new Mock();
//IElasticClient.IndexExists()函数的设置:
//我不知道IndexExists的返回类型是什么,
//所以我在这里假设它是一个动态物体
Setup(c=>c.IndexExists(indexName)).Returns(new{Exists=true});
//此处可能还需要设置IElasticCleint.DeleteIndex。
_elasticClientProvider=新建模拟();
_elasticClientProvider.Setup(c=>c.GetClient()).Returns(elasticClient.Object).Verifiable();
_searchWorker=新的ElasticSearchWorker(_elasticClientProvider);
}
//更愿意将其命名为DeleteIndexTest_GetsSearchClient,
//因为该函数所做的工作比这里检查的要多,例如,检查索引、删除索引。
[测试方法]
public void DeleteIndexTest()
{
尝试
{
searchWorker.DeleteIndex(indexName);
searchWorkerMoq.Verify(c=>c.GetClient(),Times.Once());
}
捕获(系统异常)
{
投掷;
}
}
}
这样,在这种情况下将不会有http请求