2015-02-05 3 views
8

Есть ли какой-нибудь простой способ в Autofixture для создания нового объекта с использованием его конструктора, но hard-code/указать значение, которое будет использоваться для одного параметра в конструкторе?Простой способ указать значение одного параметра конструктора?

Я вижу, что это можно сделать с помощью свойств, используя что-то вроде:

fixture.Build<MyObj>().With(x=x.Val,"hard coded value").Create()

+0

C# не имеет синтаксиса типа, который ссылается только на один параметр в методе (включая конструктор), поэтому это не реально выполнимо, если вы не потянете весь конструктор в лямбда-выражение, на что также позволяет просто создать объект непосредственно с помощью конструктора, но без AutoFixture. Какова ваша мотивация для этого? IME, часто есть хороший способ достичь большинства связанных целей по-другому, но вам, возможно, придется рассматривать проблему по-разному. –

+1

Надеюсь на небезопасный, но удобный способ, как Func , где вход будет именем параметра в виде строки. Моя общая мотивация - это единичное тестирование. Часто я хочу обновить объект, но меня беспокоит только один параметр. Возможно, значение параметра управляет вычислением или преобразованием какого-то рода. Я хочу, чтобы само значение было случайным, но тест должен знать, какое случайное значение было выбрано. Учитывая, что, возможно, модульный тест получает свойство или вызывает метод, который использует значение параметра конструктора в его работе. – SFun28

+2

некоторые варианты [этого ответа] (http://stackoverflow.com/a/27774580/11635) или [мой ответ в нижней части этого обсуждения CodePlex] (https://autofixture.codeplex.com/discussions/231342) может сделать вас счастливым –

ответ

10

Из обсуждения этого вопроса в комментариях:

Часто я хочу новый план объект, но меня беспокоит только один параметр. Возможно, значение параметра управляет вычислением или преобразованием какого-то рода. Я хочу, чтобы само значение было случайным, но тест должен знать, какое случайное значение было выбрано.

Предполагая, что это основная проблема, я попытаюсь решить эту проблему.

Задать объект

Самым простым решением является просто спросить объект, что значение есть, после того, как AutoFixture создал его:

var fixture = new Fixture(); 
var mc = fixture.Create<MyClass>(); 
var specialValue = mc.SpecialValue; 
// Do something with specialValue... 

Если вам просто нужно знать, что особое значение , но вам не нужно, чтобы он имел определенную ценность, вы можете использовать эту технику.

Это явно требует, чтобы вы указали значение из параметра конструктора как свойство (только для чтения), но это a good idea to do anyway.

Присвоить значение после создания

Если вам нужен параметр, чтобы иметь определенное значение, вы можете назначить его после создания:

var fixture = new Fixture(); 
var mc = fixture.Create<MyClass>(); 
mc.SpecialValue = "Some really special value"; 

Это требует, чтобы значение доступно как записываемое свойство. Хотя я лично не большой поклонник этого, потому что это делает объект изменчивым, многие люди уже проектируют свои объекты таким образом, и если это так, почему бы не воспользоваться им?

Использования копирование и обновление после создания

Если вы хотите, чтобы ваши объекты будут неизменны, вы все еще можете использовать вариацию выше методики. В F # вы можете использовать так называемый copy and update expressions для достижения той же цели. В F #, было бы что-то вроде:

let fixture = Fixture() 
let mc = { 
    fixture.Create<MyRecord>() 
    with SpecialValue = "Some special value!" } 

Вы можете эмулировать это в C#, давая ваши классы копирования и обновления методы, так что вы были бы в состоянии написать что-то вроде этого:

var fixture = new Fixture(); 
var mc = fixture 
    .Create<MyClass>() 
    .WithSpecialValue("Some really special value"); 

Это метод, который я использую все время в своем коде на C#. AutoFixture имеет an idiomatic assertion to test such copy and update methods.

Вводить значение для параметра

Если вы можете жить с инъекционным фиксированным значением для конкретного параметра конструктора, вы можете сделать это с помощью строительных блоков ядра AutoFixture. Этот тест показывает, как:

[Fact] 
public void CustomizeParameter() 
{ 
    var fixture = new Fixture(); 
    fixture.Customizations.Add(
     new FilteringSpecimenBuilder(
      new FixedBuilder("Ploeh"), 
      new ParameterSpecification(
       typeof(string), 
       "specialValue"))); 

    var actual = fixture.Create<MyClass>(); 

    Assert.Equal("Ploeh", actual.SpecialValue); 
} 

Однако, это вызывает этот параметр всегда быть «Ploeh» для этого fixture экземпляра. Он также рефакторинг-небезопасен, поскольку он основан на строке, ссылающейся на имя параметра.

+0

привет Марка - большое спасибо за подробный ответ. Все это хорошие способы обхода, с компромиссами точно так же, как вы их представили. Общей темой является то, что вы должны настроить свой объект так, чтобы его можно было протестировать. Для меня это немного запах кода. Не похоже, что есть способ сделать то, что я ищу, чтобы не изменять объект. – SFun28

+0

Это называется * Test-Driven Development *. Все дело в том, что тесты обеспечивают обратную связь по поводу удобства использования дизайна API. –

+0

Только если вы используете TDD =) Я думаю, что Autofixture невероятно полезен независимо от TDD. И вообще, разве это еще не запах в TDD? Единственная причина, по которой вы добавляете эти свойства, связана с недостатком Autofixture. Это не имеет никакого отношения к принципам TDD. – SFun28

Смежные вопросы