需要帮助来更好地理解Moq

我一直在看Moq的文档,这些评论太短,我不能理解它可以做的每一件事情。

我没有得到的第一件事是It.IsAny<string>(). //example using string It.IsAny<string>(). //example using string

使用它只是为了增加一些价值吗? 如果你不关心价值,我知道人们会说这个,但是如果你不关心价值,那么你可以做“一”或什么东西? 这只是更多的打字。

其次,什么时候会是一个你不关心价值的例子? 我认为Moq需要价值来匹配东西。

我没有得到它。它是完全或如何使用它。 我不明白这个例子,它试图展示什么。

接下来,我不明白什么时候使用Times (及其AtMost方法和类似的)。 为什么要限制设置的次数? 我有一些AppConfig值,我需要使用两次。 为什么我想限制一次呢? 这只会使testing失败。 这是否阻止其他人添加另一个到您的代码或东西?

我没有得到如何使用mock.SetupAllProperties(); 它与什么build立属性?

我也不明白为什么有很多不同的方式来build立一个属性,以及它们有什么不同。 该文件有:

 SetupGet(of property) SetupGet<TProperty> 

我注意到Moq中有很多东西显示()<> – 它们之间有什么区别,它们看起来像在使用什么?

我也不明白为什么他们有SetupGet 。 你会不会使用SetupSet来设置属性? SetupSet有五种不同的方式在文档中使用它。 另外一个叫做SetupProperty 。 所以我不明白为什么有这么多。

在一个侧面说明,我想知道在lambda使用的variables是否独立于其他lambda。 例如:

 mock.setup(m => m.Test); stop.setup(m => m.Test); 

这会好吗或者variablesm之间会有一些冲突吗?

最后,我正在看这个video ,我想知道它是否显示Visual Studio。 他的Intellisense看起来不一样。 一个灯泡popup了他(我很高兴我不这样做,因为它带回了netbeans痛苦的回忆),并且有从一个开放的支撑线到右支撑等行。

谢谢 :)

It's / It.Is

当你在被测代码中传递一个新的引用types时,这些可能是有用的。 例如,如果你有一个方法沿着: –

 public void CreatePerson(string name, int age) { Person person = new Person(name, age); _personRepository.Add(person); } 

您可能想要检查存储库上调用的add方法

 [Test] public void Create_Person_Calls_Add_On_Repository () { Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>(); PersonManager manager = new PersonManager(mockRepository.Object); manager.CreatePerson("Bob", 12); mockRepository.Verify(p => p.Add(It.IsAny<Person>())); } 

如果你想使这个testing更加明确,你可以使用It.Is通过提供一个谓词person对象必须匹配

 [Test] public void Create_Person_Calls_Add_On_Repository () { Mock<IPersonRepository> mockRepository = new Mock<IPersonRepository>(); PersonManager manager = new PersonManager(mockRepository.Object); manager.CreatePerson("Bob", 12); mockRepository.Verify(pr => pr.Add(It.Is<Person>(p => p.Age == 12))); } 

如果用于调用add方法的person对象没有将age属性设置为12,则testing将通过exception进行testing。

如果你有一个方法: –

 public void PayPensionContribution(Person person) { if (person.Age > 65 || person.Age < 18) return; //Do some complex logic _pensionService.Pay(500M); } 

你可能要testing的一个事情是,当一个65岁以上的人进入该方法时,薪酬方法不会被调用

 [Test] public void Someone_over_65_does_not_pay_a_pension_contribution() { Mock<IPensionService> mockPensionService = new Mock<IPensionService>(); Person p = new Person("test", 66); PensionCalculator calc = new PensionCalculator(mockPensionService.Object); calc.PayPensionContribution(p); mockPensionService.Verify(ps => ps.Pay(It.IsAny<decimal>()), Times.Never()); } 

类似地,可以想象在迭代集合的情况下,为集合中的每个项目调用一个方法,并且要确保它被调用了一定的次数,其他时候您根本不关心。

SetupGet / SetupSet

你需要注意的是,他们反映了你的代码如何与模拟交互,而不是你如何设置模拟

 public static void SetAuditProperties(IAuditable auditable) { auditable.ModifiedBy = Thread.CurrentPrincipal.Identity.Name; } 

在这种情况下,代码将设置IAuditable实例的ModifiedBy属性,同时获取IPrincipal的当前实例的Name属性

 [Test] public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() { Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>(); Mock<IAuditable> mockAuditable = new Mock<IAuditable>(); mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test"); Thread.CurrentPrincipal = mockPrincipal.Object; AuditManager.SetAuditProperties(mockAuditable.Object); mockPrincipal.VerifyGet(p => p.Identity.Name); mockAuditable.VerifySet(a => a.ModifiedBy = "test"); } 

在这种情况下,我们在IPrincipal的模拟上设置name属性,所以当在Identity的Name属性上调用getter时,它将返回“test”,我们不会设置属性本身。

SetupProperty / SetupAllProperties

看看上面的testing,如果它被改为阅读

 [Test] public void Accesses_Name_Of_Current_Principal_When_Setting_ModifiedBy() { Mock<IPrincipal> mockPrincipal = new Mock<IPrincipal>(); Mock<IAuditable> mockAuditable = new Mock<IAuditable>(); mockPrincipal.SetupGet(p => p.Identity.Name).Returns("test"); var auditable = mockAuditable.Object; Thread.CurrentPrincipal = mockPrincipal.Object; AuditManager.SetAuditProperties(auditable); Assert.AreEqual("test", auditable.ModifiedBy); } 

testing会失败。 这是因为由Moq创build的代理实际上并没有在属性的set方法中做任何事情,除非你告诉它。 在影响模拟对象看起来有点像这样

 public class AuditableMock : IAuditable { public string ModifiedBy { get { return null; } set { } } } 

为了让testing通过,你必须告诉Moq设置属性以具有标准的属性行为。 你可以通过调用SetupProperty来做到这一点,模拟看起来更像

 public class AuditableMock : IAuditable { public string ModifiedBy { get; set; } } 

并且上面的testing将会通过,因为“testing”值现在将被存储在模拟中。 当嘲笑复杂的对象时,您可能希望对所有属性执行此操作,因此可以使用SetupAllProperties快捷方式

最后,IDE中的灯泡是resharper插件。

如果你不关心一个物业的确切价值,那么使用它会好得多。因为你清楚地知道确切的价值并不重要。 如果您将其硬编码为“abc”,那么您所testing的代码取决于以“a”开始还是以“c”结尾或长度为3个字符等是不明确的。