我正在使用 Autofixture 生成我的测试模型,但在一个实例中,它说我的模型有一个我找不到的循环引用。失败的模型是类RepresentationExpense,我唯一能想到的是它与继承相关,因为该类Expense没有相同的问题:
public class RepresentationExpense : Expense
{
public string GuestName { get; private set; }
public string GuestCompany { get; private set; }
public RepresentationExpense(ExpenseId id, ExpenseReportId reportId, EmployeeId employeeId, string description, Payment payment, DateTime created, PaymentMethod paymentMethod, ReceiptId receiptId, string guestName, string guestCompany, string comment = null)
: base(id, reportId, employeeId, description, payment, created, paymentMethod, CategoryType.Representation, receiptId, comment)
{
Verify.ArgumentNotNull(guestName, "guestName");
Verify.ArgumentNotNull(guestCompany, "guestCompany");
GuestName = guestName;
GuestCompany = guestCompany;
}
}
public class …Run Code Online (Sandbox Code Playgroud) 在这里查看帖子时,看起来我应该能够创建多个对象,使用CreateMany()它们迭代它们foreach,然后将它们作为数组返回.
我所看到的是,每次迭代似乎每次都会创建新对象.这是预期的行为吗?
要创建的实体:
public class TestEntity
{
public int Id { get; private set; }
public string SomeString { get; set; }
public void SetId(int value)
{
this.Id = value;
}
}
Run Code Online (Sandbox Code Playgroud)
示例Program.cs:
private static int id;
static void Main(string[] args)
{
var fixture = new Fixture();
IEnumerable<TestEntity> testEntities =
fixture.Build<TestEntity>().CreateMany(5);
Output(testEntities);
foreach (var testEntity in testEntities)
{
testEntity.SetId(id++);
Console.WriteLine(
string.Format("CHANGED IN FOREACH:: hash: {0}, id: {1}, string: {2}",
testEntity.GetHashCode(), testEntity.Id, testEntity.SomeString));
}
Output(testEntities); …Run Code Online (Sandbox Code Playgroud) 我有这样一堂课:
public class ViewModel
{
public IPagination<Data> List { get; set; } // interface!
public SearchFilter SearchFilter { get; set; }
public string Test { get; set; }
}
public class SearchFilter
{
public string Name { get; set; }
}
Run Code Online (Sandbox Code Playgroud)
应在IPagination接口周围创建动态代理,代理应填充测试数据.现在可以让AutoFixture创建一个ViewModel类型的实例吗?请注意,我只知道运行时的类型(typeof(ViewModel)).
到现在为止我知道我可以这样做:
var context = new SpecimenContext(fixture.Compose());
var value = context.Resolve(new SeededRequest(typeof(ViewModel), null))
Run Code Online (Sandbox Code Playgroud) 代码:
IFixture fixture = new Fixture().Customize(new AutoMoqCustomization());
fixture.Customize<ViewDataDictionary>(c => c.Without(x => x.ModelMetadata));
var target = fixture.CreateAnonymous<MyController>();
Run Code Online (Sandbox Code Playgroud)
例外:
System.Reflection.TargetInvocationException:System.Reflection.TargetInvocationException:调用目标已抛出异常.---> System.NotImplementedException:未实现方法或操作.
MyController() 需要3个参数.
我试着在答案中描述的修复在这里,但它是行不通的.
我在测试中有一组工作命令性代码,我试图将其归结为一个基本的测试约定.
我的测试如下所示:
[Theory, BasicConventions]
public void GetVersionOnSiteVersionControllerReturnsASiteVersion(IFixture fixture)
{
fixture.OmitAutoProperties = true;
SiteVersion expected = fixture.Create<SiteVersion>();
SiteVersion actual = null;
var sut = fixture.Create<SiteVersionController>();
var response = sut
.GetSiteVersion()
.ExecuteAsync(new CancellationToken())
.Result
.TryGetContentValue<SiteVersion>(out actual);
actual.AsSource().OfLikeness<SiteVersion>().ShouldEqual(expected);
}
Run Code Online (Sandbox Code Playgroud)
我还有一个允许它工作的自定义,即通过设置HttpConfiguration和HttpRequestMessage默认的非空值.
public class ApiControllerCustomization : ICustomization
{
public void Customize(IFixture fixture)
{
var origin = fixture.OmitAutoProperties;
fixture.OmitAutoProperties = true;
var sut = fixture.Create<SiteVersionController>();
sut.Configuration = fixture.Create<HttpConfiguration>();
sut.Request = fixture.Create<HttpRequestMessage>();
fixture.Inject<SiteVersionController>(sut);
fixture.OmitAutoProperties = origin;
}
}
Run Code Online (Sandbox Code Playgroud)
首先,这看起来很难看,但如果我使用Build <>().omit().with(config).with(request),它会关闭构建这些实例所需的automoq自定义.
其次,这仅适用于SiteVersionController.对于我所有的ApiControllers,我更倾向于概括一下(也许这是一个坏主意,但在我尝试之前我不会知道).
基本上我的约定如下: 对于所有ApiControllers,创建它们没有自动属性但是将http配置和请求消息属性设置为默认的非空值
我的测试要求我将Response不可变Rsvp对象(见下文)的属性设置为特定值.
public class Rsvp
{
public string Response { get; private set; }
public Rsvp(string response)
{
Response = response;
}
}
Run Code Online (Sandbox Code Playgroud)
我最初尝试使用Build<Rsvp>().With(x => x.Rsvp, "Attending"),但意识到这只支持可写属性.
我替换了Build<Rsvp>().FromFactory(new Rsvp("Attending")).这可行,但对于更复杂的对象来说很麻烦,因为它们与某些属性无关.
例如,如果Rsvp对象具有CreatedDate属性,则实例化对象的这种方法将迫使我编写Build<Rsvp>().FromFactory(new Rsvp("Attending", fixture.Create<DateTime>())).
有没有办法只为不可变对象指定含义属性的值?
我正在阅读大量文档和示例,了解如何正确地对标题中的三个组件进行单元测试.我想出了一种针对我的业务逻辑的方法的测试方法,但它感觉非常笨重和肮脏.
我想从那些对这个主题更有经验的人那里得到一些反馈,看看我如何改进它.
这是代码,解释如下:
[Fact]
public void ShouldGetItemWithSameId()
{
var fixture = new Fixture().Customize(new AutoMoqCustomization());
var facade = fixture.Freeze<Mock<IDataFacade>>();
facade.Setup(c => c.Get(It.IsAny<int>())).Returns((int i) => new Item { Key = i });
var sut = fixture.Create<BusinessLogic>();
var expected = fixture.Create<int>();
Assert.Equal(expected, sut.Get(expected).Key);
}
Run Code Online (Sandbox Code Playgroud)
我的BusinessLogic类使用一个IDataFacade构造函数参数,该参数负责在其Get(int)方法中检索具有相同Id的项目,非常基本的东西.
我冻结了IDataFacade模拟并将其设置为构造一个与Id匹配的对象It.IsAny<int>.然后我创建我的SUT并测试它.工作良好.
我想了解一下,考虑到以下方面我是否可以改进:
Query方法,它接受一个包含很多属性的类,这些属性将用作匹配被查询类型的属性的过滤器.在这种情况下,我不知道如何正确地执行模拟的"设置"部分,因为我必须初始化所有或接近所有返回类型的属性,并且在这种情况下它不是单个项目但是整个系列我有一些其他测试用Theory,AutoMoqData但我无法使用这种方法实现这个测试(我认为更复杂的测试),所以我Fact用手动实例化的夹具切换回普通.
任何帮助将非常感激.
参数的CreateMany重载T seed实际上做了什么?我试图播种,但种子似乎对创建的对象没有影响.例如,我期待如果我的种子具有类型的属性string,那么:
字符串值将用于在所有新创建的对象中填充该属性
或者在所有新创建的对象中设置该属性时,字符串值将用作前缀
我正在尝试创建一种在单元测试中测试字符串参数的简单方法,对于大多数字符串参数,我想在参数为Null,Empty或仅包含空格时检查行为.
在大多数情况下,我使用string.IsNullOrWhiteSpace()检查参数,如果它具有这三个值中的一个,则抛出异常.
现在进行单元测试,似乎我必须为每个字符串参数编写三个单元测试.一个用于空值,一个用于空值,一个用于空白.
想象一个带有3或4个字符串参数的方法,然后我需要编写9或12个单元测试...
任何人都可以想出一个简单的方法来测试这个吗?也许使用AutoFixture?
我正在写一些单元测试,并有一个类称为Account具有
public Guid AccountId {get;set;}
public IEnumerable<string> EmailAddresses {get;set;}
etc...
Run Code Online (Sandbox Code Playgroud)
我想使用autofixture来创建帐户,但我无法获得电子邮件格式.
我试过了
fixture.Register<string>(() => string.Format("{0}@acme.com", fixture.Create<string>()));
Run Code Online (Sandbox Code Playgroud)
但那会导致循环问题.
我能做到这一点
fixture.Register<string>(() => string.Format("{0}@acme.com", fixture.Create<int>()));
Run Code Online (Sandbox Code Playgroud)
但我宁愿在地址的开头有一个字符串.
编辑 感谢这两个答案我在这里写了一个摘要和其他几个场景作为帖子 - http://nodogmablog.bryanhogan.net/2016/04/customizing-a-specific-string-inside-a-class-using -autofixture /
autofixture ×10
c# ×10
unit-testing ×6
.net ×1
automoq ×1
immutability ×1
moq ×1
test-data ×1
testing ×1
xunit.net ×1