我有用于设置和拆除NHibernate的通用代码,我几乎所有的测试都需要它.有没有办法在一个地方包含"需要所有测试"代码,然后将其应用于所有测试?(比如Nunit setup和teardown方法)
[Subject("Accessing the TAE allocation page")]
public class when_a_request_to_the_tae_allocation_page_is_made
{
Establish context = () => NHTestHelper.StartTest(); //need for all tests
Because of = () => result = new AllocationController(true).Index();
It should_display_the_page = () => result.ShouldBeAView();
Cleanup nh = () => NHTestHelper.EndTest(); //need for all tests
static ActionResult result;
}
Run Code Online (Sandbox Code Playgroud) 我有IAudioProcessor一个单一方法的接口IEnumerable<Sample> Process(IEnumerable<Sample> samples).虽然它不是接口本身的要求,但我想确保我的所有实现遵循一些通用规则,例如:
为这些创建测试并不难,但我必须为每个实现复制并粘贴这些测试.我想避免这种情况.
我想做这样的事情(注意属性GenericTest和类型参数):
[GenericTest(typeof(AudioProcessorImpl1Factory))]
[GenericTest(typeof(AudioProcessorImpl2Factory))]
[GenericTest(typeof(AudioProcessorImpl3Factory))]
public class when_processed_audio_is_returned<TSutFactory>
where TSutFactory : ISutFactory<IAudioProcessor>, new()
{
static IAudioProcessor Sut = new TSutFactory().CreateSut();
protected static Context _ = new Context();
Establish context = () => _.Original = Substitute.For<IEnumerable<ISample>>();
Because of = () => Sut.Process(_.Original);
It should_not_have_enumerated_the_original_samples = () =>
{
_.Original.DidNotReceive().GetEnumerator();
((IEnumerable)_.Original).DidNotReceive().GetEnumerator();
};
}
Run Code Online (Sandbox Code Playgroud)
这样的事情可能吗?
我最近进入BDD并认为它有很大的希望,作为一种方式,让我们作为开发人员为他们创建的应用程序中的利益相关者的声音.你最喜欢的BDD框架是什么?为什么?
之前使用过MbUnit,我们正在使用MSpec进行单元测试.
我习惯说
Assert.IsTrue(status, "Status should be true");
Run Code Online (Sandbox Code Playgroud)
在MbUnit中,即向断言添加消息,如果失败则输出该消息.
我在MSpec中找不到任何相应的功能.我正在测试一些XML验证,如果失败,我想报告验证错误消息.所以我的MSpec代码看起来像
string message;
bool isValid = ValidateXml(myXml, out message);
isValid.ShouldBeTrue();
Run Code Online (Sandbox Code Playgroud)
但是message如果ShouldBeTrue()失败,我希望能够将测试输出添加到测试输出中.
这可能吗?
在我的最新项目中,Moq让我有点疯狂.我最近升级到版本4.0.10827,我注意到在我看来是一个新的行为.
基本上,当我MakeCall在我正在测试的代码中调用我的模拟函数(在本例中)时,我传入一个object(TestClass).我正在测试的代码TestClass在调用之前和之后对对象进行了更改MakeCall.一旦代码完成,我就调用Moq的Verify功能.我的期望是,Moq将记录我传入的完整对象MakeCall,可能通过深度克隆等机制.通过这种方式,我将能够验证是否MakeCall使用我希望调用它的确切对象进行调用.不幸的是,这不是我所看到的.
我试图在下面的代码中说明这一点(希望在此过程中澄清一点).
TestClass对象.它的Var财产设置为"one". mockedObject,这是我的测试主题. MakeCall方法mockedObject(顺便说一下,示例中使用的Machine.Specifications框架允许When_Testing从上到下读取类中的代码). TestClass使用Var值为"one".正如我所预料的那样,这成功了. TestClass通过重新分配Var属性来更改原始对象"two". MakeCall调用.这失败了,虽然我期待它是真的. TestClass"one"MakeCall实际上是由TestClass具有值的对象调用的"two".这成功了,虽然我最初预计它会失败. 对我来说,似乎很清楚Moq只保留对原始TestClass对象的引用,允许我改变其值而不受惩罚,对我的测试结果产生不利影响.
关于测试代码的一些注意事项. IMyMockedInterface是我嘲笑的界面. TestClass是我传递给该MakeCall方法的类,因此用于演示我遇到的问题.最后,When_Testing是包含测试代码的实际测试类.它正在使用Machine.Specifications框架,这就是为什么有一些奇怪的项目('因为','它应该...').这些只是框架调用以执行测试的委托.如果需要,应该很容易删除它们并将包含的代码放入标准函数中.我把它留在这种格式中,因为它允许所有Validate调用完成(与'Arrange,Act Assert'范例相比).只是为了澄清,下面的代码不是我遇到问题的实际代码.它只是为了说明问题,因为我在多个地方看到了同样的行为.
using Machine.Specifications;
// …Run Code Online (Sandbox Code Playgroud) 我一直在使用MSpec,我真的很喜欢它.我发现要让ReSharper识别我的规格,我需要使用SubjectAttribute.
我想知道,在[Subject()]属性中放入什么是最好的东西?
如果我正在做BDD,那么我不知道被测试的类型所以[Subject(typeof(thingy))]似乎为时过早.可以在以后添加,我想一旦编写代码.
所以留下文本版本,[Subject("some text")].但放在那里最好的是什么?
无论我做什么,它似乎都不会影响我在ReSharper中获得的输出.我想在某种程度上这取决于个人偏好,但我想知道这里是否有任何约定?
我正在通过Kent Beck的TDD作为学术练习,但是使用MSpec来编写测试.在下面的工作示例中,我想介绍一个扭曲,以便我不能简单地将文本复制出来,我发现这种方式我倾向于遇到我必须解决的问题,因此,最终学习更多.我相信这是其中一个场合.
我通过肯特的"钱"例子.这是我的类结构:

我有以下两个测试环境:
[Subject(typeof(Money), "Equality")]
public class when_comparing_different_classes_for_equality
{
Because of = () => FiveFrancs = new Franc(5, "CHF");
It should_equal_money_with_currency_set_to_francs = () => FiveFrancs.Equals(new Money(5, "CHF")).ShouldBeTrue();
static Franc FiveFrancs;
}
[Subject(typeof(Franc), "multiplication")]
public class when_multiplying_a_franc_amount_by_an_integer
{
Because of = () => FiveFrancs = new Franc(5, null);
It should_be_ten_francs_when_multiplied_by_2 = () => FiveFrancs.Times(2).ShouldEqual(Money.Franc(10));
It should_be_fifteen_francs_when_multiplied_by_3 = () => FiveFrancs.Times(3).ShouldEqual(Money.Franc(15));
static Franc FiveFrancs;
}
Run Code Online (Sandbox Code Playgroud)
Times()方法返回一个包含结果的Money类型的新对象,即对象是不可变的.上面的第一个上下文传递,表明Equals正在按预期工作,即它忽略了对象类型,只要它们都是从Money继承的,并且只比较金额和货币字段是相等的.第二个上下文失败,输出类似于:
Machine.Specifications.SpecificationException
Expected: TDDByExample.Money.Specifications.Franc:[15]
But was: TDDByExample.Money.Specifications.Money:[15]
at TDDByExample.Money.Specifications.when_multiplying_a_franc_amount_by_an_integer.<.ctor>b__2() in MoneySpecs.cs: line 29
Run Code Online (Sandbox Code Playgroud)
平等定义为金额(价值)和货币相同; 应该忽略对象的实际类型,因此预期的结果是,如果我正在测试与Money或Franc对象的相等性,只要金额和货币字段相同,则无关紧要.但是,事情没有按计划进行.调试时,我的Equals()方法甚至没有被调用.显然我在这里并不理解.我确信当我知道它时,解决方案将会非常明显,但我看不出它.任何人都可以提出一个建议,我需要做些什么来使这项工作?
这是Equals()的实现: …
我正在尝试将对虚假对象的调用代理到实际实现.这样做的原因是我希望能够使用Machine.Specifications的WasToldTo和WhenToldTo,它仅适用于接口类型的伪造.
因此,我正在执行以下操作来代理对我的真实对象的所有调用.
public static TFake Proxy<TFake, TInstance>(TFake fake, TInstance instance) where TInstance : TFake
{
fake.Configure().AnyCall().Invokes(x => x.Method.Invoke(instance, x.Arguments.ToArray()));
return fake;
}
Run Code Online (Sandbox Code Playgroud)
我会像这样使用它.
var fake = Proxy<ISomeInterface, SomeImplementation>(A.Fake<ISomeInterface>(), new SomeImplementation());
//in my assertions using Machine.Specifications (reason I need a fake of an interface)
fake.WasToldTo(x => x.DoOperation());
Run Code Online (Sandbox Code Playgroud)
然而问题是这只适用于void方法,因为Invokes方法没有对返回值做任何事情.(Action param代替Func)
然后我尝试使用WithReturnValue方法执行此操作.
public static TFake Proxy(TFake fake, TInstance instance) where TInstance : TFake
{
fake.Configure().AnyCall()..WithReturnType().Invokes(x => x.Method.Invoke(instance, x.Arguments.ToArray()));
fake.Configure().AnyCall()..WithReturnType().Invokes(x => x.Method.Invoke(instance, x.Arguments.ToArray()));
fake.Configure().AnyCall()..WithReturnType().Invokes(x => x.Method.Invoke(instance, x.Arguments.ToArray()));
//etc.
return fake;
}
Run Code Online (Sandbox Code Playgroud)
然而,Invokes方法仍然不能按我想要的方式工作(仍然是Action而不是Func).所以仍然没有使用返回值.
有没有办法用当前的最新版本实现这一目标?
我已经在FakeItEasy …
我们使用Machine.Specification作为我当前项目的测试框架.这适用于我们测试的大部分内容.但是,我们有许多视图模型,其中我们具有"格式化"属性,这些属性采用一些原始数据,应用一些逻辑,并返回该数据的格式化版本.
由于格式化涉及逻辑(空检查,零特殊情况等),我想测试一些可能的数据值,包括边界条件.对我来说,这不是MSpec的正确用例,我们应该深入到像NUnit这样的东西,我可以使用类似[TestCase]属性的东西来编写数据驱动的测试.
有没有一种干净,简单的方法在MSpec中编写这种测试,或者我觉得我们应该使用不同的工具进行这种测试?
查看模型
public class DwellingInformation
{
public DateTime? PurchaseDate { get; set; }
public string PurchaseDateFormatted
{
if(PurchaseDate == null)
return "N/A";
return PurchaseDate.Value.ToShortDateString();
}
public int? ReplacementCost { get; set; }
public string ReplacementCostFormatted
{
if(ReplacementCost == null)
return "N/A";
if(ReplacementCost == 0)
return "Not Set";
return ReplacementCost.ToString("C0");
}
// ... and so on...
}
Run Code Online (Sandbox Code Playgroud)
MSpec测试
public class When_ReplacementCost_is_null
{
private static DwellingInformation information;
Establish context = () =>
{
information = new DwellingInformation { ReplacementCost = …Run Code Online (Sandbox Code Playgroud) mspec ×10
unit-testing ×5
c# ×4
.net ×3
bdd ×3
tdd ×2
appharbor ×1
asp.net-mvc ×1
assert ×1
fakeiteasy ×1
mocking ×1
moq ×1
nhibernate ×1
nspec ×1