Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 太多的接口和包装?_C#_Unit Testing_Mocking_Moq - Fatal编程技术网

C# 太多的接口和包装?

C# 太多的接口和包装?,c#,unit-testing,mocking,moq,C#,Unit Testing,Mocking,Moq,我慢慢地开始掌握单元测试和模拟的窍门,但这是一个缓慢的过程。我尝试过对这个Active Directory代码进行单元测试。这个问题与广告没有严格的关系 class ActiveDirectoryQueryer { DirectorySearcher mSearcher; public ActiveDirectoryQueryer() { var searcher = new DirectorySearcher(...); } public voi

我慢慢地开始掌握单元测试和模拟的窍门,但这是一个缓慢的过程。我尝试过对这个Active Directory代码进行单元测试。这个问题与广告没有严格的关系

class ActiveDirectoryQueryer {    
   DirectorySearcher mSearcher;

   public ActiveDirectoryQueryer() {
      var searcher = new DirectorySearcher(...);
   }

   public void GetAllMailEntries() {
      MailEntries =
         mSearcher
         .FindAll()
         .Select(result => result.GetDirectoryEntry())
         .Select(BuildNewADUser)
         .ToList();
   }

   static ActiveDirectoryUser BuildNewADUser(DirectoryEntry pDirectoryEntry) {
      return ActiveDirectoryUser.Create(
         pDirectoryEntry.Guid,
         (pDirectoryEntry.Properties["name"].Value ?? "").ToString(),
         (pDirectoryEntry.Properties["mail"].Value ?? "").ToString()
      );
   }
因此,我想对
GetAllMailEntries
方法进行单元测试。为了使用MOQ实现这一点,我不得不手动为各种.NET类型生成接口和包装,并将上面的许多引用改为接口(如
IDirectoryEntry
)。下面的每个
ixxx
接口都有一个关联的包装类
XxxxWrapper
。为了这一个测试,我总共添加了至少12个新的源文件。下面是我在单元测试中得出的结论:

[TestMethod]
public void TestGetAllMailEntries() {
   var mockSearcher = new Mock<IDirectorySearcher>();
   var mockResultCollection = new Mock<ISearchResultCollection>();
   var mockSearchResult = new Mock<ISearchResult>();
   var mockDirectoryEntry = new Mock<IDirectoryEntry>();
   var mockPropertyCollection = new Mock<IPropertyCollection>();
   var nameMockPropertyValueCollection = new Mock<IPropertyValueCollection>();
   var mailMockPropertyValueCollection = new Mock<IPropertyValueCollection>();

   const string name = "SomeNameValue";
   const string mailAddress = "SomeMailAddress";

   nameMockPropertyValueCollection.SetupGet(pvc => pvc.Value).Returns(name);
   mailMockPropertyValueCollection.SetupGet(pvc => pvc.Value).Returns(mailAddress);
   mockPropertyCollection.SetupGet(pc => pc["name"]).Returns(nameMockPropertyValueCollection.Object);
   mockPropertyCollection.SetupGet(pc => pc["mail"]).Returns(mailMockPropertyValueCollection.Object);
   mockDirectoryEntry.SetupGet(de => de.Properties).Returns(mockPropertyCollection.Object);
   mockSearchResult.Setup(sr => sr.GetDirectoryEntry()).Returns(mockDirectoryEntry.Object);
   mockResultCollection.Setup(results => results.GetEnumerator()).Returns(new List<ISearchResult> { mockSearchResult.Object }.GetEnumerator());
   mockSearcher.Setup(searcher => searcher.FindAll()).Returns(mockResultCollection.Object);

   var queryer = new ActiveDirectoryQueryer(mockSearcher.Object);
   queryer.GetAllMailEntries();
   Assert.AreEqual(1, queryer.MailEntries.Count());
   var entry = queryer.MailEntries.Single();
   Assert.AreEqual(name, entry.Name);
   Assert.AreEqual(mailAddress, entry.EmailAddress);
}
[TestMethod]
public void TestGetAllMailEntries(){
var mockSearcher=new Mock();
var mockResultCollection=new Mock();
var mockSearchResult=new Mock();
var mockDirectoryEntry=new Mock();
var mockPropertyCollection=new Mock();
var nameMockPropertyValueCollection=new Mock();
var mailMockPropertyValueCollection=new Mock();
const string name=“SomeNameValue”;
const string mailAddress=“SomeMailAddress”;
nameMockPropertyValueCollection.SetupGet(pvc=>pvc.Value).Returns(name);
mailMockPropertyValueCollection.SetupGet(pvc=>pvc.Value).Returns(mailAddress);
mockPropertyCollection.SetupGet(pc=>pc[“name”])。返回(nameMockPropertyValueCollection.Object);
mockPropertyCollection.SetupGet(pc=>pc[“mail”])。返回(mailMockPropertyValueCollection.Object);
SetupGet(de=>de.Properties).Returns(mockPropertyCollection.Object);
mockSearchResult.Setup(sr=>sr.GetDirectoryEntry())。返回(mockDirectoryEntry.Object);
mockResultCollection.Setup(results=>results.GetEnumerator())。返回(新列表{mockSearchResult.Object}.GetEnumerator());
Setup(searcher=>searcher.FindAll()).Returns(mockResultCollection.Object);
var queryer=new-ActiveDirectoryQueryer(mockSearcher.Object);
GetAllMailEntries();
AreEqual(1,queryer.MailEntries.Count());
var entry=queryer.MailEntries.Single();
Assert.AreEqual(name,entry.name);
Assert.AreEqual(mailAddress、entry.EmailAddress);
}

有这么多接口和包装类是正常的吗?(包装器是必要的,因为.NET类型无法以其他方式实现我的接口。)

我认为我的问题是镜像.NET结构太接近。我不应该把每一个.NET类型都包装起来,直到我得到了原语。相反,我应该利用第一次机会尽快删除所有依赖项。在本例中,它使用
DirectorySearcher
类和
FindAll
方法

DirectorySearcher.FindAll
返回一个
SearchResultCollection
,但是我应该更多地利用它,而不是将我的“wrapper”类看作是.NET类型的适配器

忽略
IDisposable
和其他不必要的代码的实现,我的包装器如下所示:

public interface IDirectorySearcher : IDisposable {
   ISearchResultCollection FindAll();
}

class DirectorySearcherWrapper : IDirectorySearcher {
   DirectorySearcher mDirectorySearcher;

   DirectorySearcherWrapper(DirectorySearcher pDirectorySearcher) {
      mDirectorySearcher = pDirectorySearcher;
   }

   public static IDirectorySearcher Wrap(DirectorySearcher pDirectorySearcher) {
      return new DirectorySearcherWrapper(pDirectorySearcher);
   }

   public ISearchResultCollection FindAll() {
      return SearchResultCollectionWrapper.Wrap(mDirectorySearcher.FindAll());
   }
}
相反,我应该借此机会在这里停止所有依赖关系。我不必返回.NET类型,甚至不必只返回.NET类型的包装器,我现在可以使用这个接口返回我想要的任何东西。IE:如果我想从
FindAll
方法中得到的是一堆
ActiveDirectoryUser
s,那么就返回它

然后,我的代码变成:

public interface IDirectorySearcher : IDisposable {
   IEnumerable<ActiveDirectoryUser> FindAll();
}

class DirectorySearcherWrapper : IDirectorySearcher {
   DirectorySearcher mDirectorySearcher;

   DirectorySearcherWrapper(DirectorySearcher pDirectorySearcher) {
      mDirectorySearcher = pDirectorySearcher;
   }

   public static IDirectorySearcher Wrap(DirectorySearcher pDirectorySearcher) {
      return new DirectorySearcherWrapper(pDirectorySearcher);
   }

   public IEnumerable<ActiveDirectoryUser> FindAll() {
      return
         mDirectorySearcher
         .FindAll()
         .Cast<SearchResult>()
         .Select(result => result.GetDirectoryEntry())
         .Select(/*BuildNewADUser*/)
         .ToList();
   }
}
单元测试变成:

[TestMethod]
public void TestGetAllMailEntries2() {
   var mockSearcher = new Mock<IDirectorySearcher>();

   mockSearcher
   .Setup(s => s.FindAll())
   .Returns(new[] {
      ActiveDirectoryUser.Create(new Guid(), "Name", "EmailAddress")
   });

   var queryer = new ActiveDirectoryQueryer(mockSearcher.Object);
   queryer.GetAllMailEntries();
   Assert.AreEqual(1, queryer.MailEntries.Count());
   var entry = queryer.MailEntries.Single();
   Assert.AreEqual("Name", entry.Name);
   Assert.AreEqual("EmailAddress", entry.EmailAddress);
}
[TestMethod]
public void TestGetAllMailEntries2(){
var mockSearcher=new Mock();
模拟搜索者
.Setup(s=>s.FindAll())
.返回(新[]{
创建(新Guid(),“名称”,“电子邮件地址”)
});
var queryer=new-ActiveDirectoryQueryer(mockSearcher.Object);
GetAllMailEntries();
AreEqual(1,queryer.MailEntries.Count());
var entry=queryer.MailEntries.Single();
Assert.AreEqual(“Name”,entry.Name);
Assert.AreEqual(“EmailAddress”,entry.EmailAddress);
}

我简要回顾了您的设置,以下内容很快让我印象深刻。而不是静态的“BuildNewADUser”函数。把它放到一个新的服务(一个接口)中,并提供它所需要的。例如,IActiveDirectoryUserFactory.Create(Guid id、字符串名称、字符串电子邮件)返回ActiveDirectoryUser。现在,只需模拟一个接口和一个方法,就可以更轻松地对初始类进行单元测试。@Atoms谢谢,我有点喜欢这个想法,但我不认为这会让我不模拟
DirectorySearcher
。这看起来好多了!我想你已经把事情弄明白了。正如您自己所了解的,我上面的建议主要是关于删除外部依赖项(特别是在讨厌的静态方法中)。依赖关系很好,但如果它们都是实现内部的,那么这通常是理想的。当您在接口中公开外部依赖项时,它将需要一个实现或一个模拟。。。想想看,我到底做了什么?我把我想测试的方法移到了另一个类中,最终没有实际测试它。。。我在周三之前不会再做这方面的工作,但我不完全确定这是否更好。我提出这个建议的原因是,一个班级有那么多需要嘲笑的项目,这显然表明这个班级做得太多了。您是对的,最终,在某个地方,您可能不得不直接使用这些active directory对象。但是如果您的设计被正确地分解,那么创建单元测试就变得容易多了。换言之;类更容易测试,但要测试的类更多。根据我的经验,这一直是件好事。
[TestMethod]
public void TestGetAllMailEntries2() {
   var mockSearcher = new Mock<IDirectorySearcher>();

   mockSearcher
   .Setup(s => s.FindAll())
   .Returns(new[] {
      ActiveDirectoryUser.Create(new Guid(), "Name", "EmailAddress")
   });

   var queryer = new ActiveDirectoryQueryer(mockSearcher.Object);
   queryer.GetAllMailEntries();
   Assert.AreEqual(1, queryer.MailEntries.Count());
   var entry = queryer.MailEntries.Single();
   Assert.AreEqual("Name", entry.Name);
   Assert.AreEqual("EmailAddress", entry.EmailAddress);
}