2014-03-19 3 views
4

Я использую Moq, чтобы издеваться над некоторыми объектами ранней связи CRM, чтобы я мог тестировать свои плагины. Я хочу подделать или издеваться над Активной учетной записью, но проблема в том, что statecode - это только чтение, а не виртуальное поле. Например, когда я пытаюсь дразнить Account ранней переплет сущности, чтобы указать, что он должен вернуться, если его statecode доступен я получаю:Mocking/Faking Active CRM Entity

var accountMock = new Mock<Account>(); 
accountMock.SetupGet(x => x.statecode).Returns(AccountState.Active); 

и NotSupportedException брошен: Invalid setup on a non-virtual (overridable in VB) member: x => x.statecode. Это происходит потому, что в раннем классе обертки для учетной записи, предоставленной SDK, поле statecode не является виртуальным. Мок не может переопределить его, как я прошу его сделать! Я подумал: «Почему бы не сделать обертку для класса Account?».

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

В настоящее время я работаю с откатом, чтобы прочитать XML-сериализованную учетную запись, которая уже активна из файла, но это действительно побеждает цель насмешки, поскольку у меня в основном есть образец файла данных для чтения. Это работает, но это не насмешка.

Мое самое многообещающее мероприятие заключалось в создании обертки TestAccount, которая расширила учетную запись и заставила ее выглядеть так, как вы могли бы установить, а также получить statecode. Это было самым многообещающим, потому что я мог на самом деле высмеять этот класс TestAccount, сообщив об этом службе OrganizationService с активными statecode и statuscode (что он и сделал!) И подтвердите, что когда он был типа Entity, у него были правильные поля. Он не удался, когда экземпляр TestAccount был в конечном итоге преобразован в ранний тип учетной записи. Настройка statuscode застряла, но настройка statecode не предполагала, потому что нет публичного сеттера для statecode, как есть для statuscode.

Я объясню с помощью кода!

// Wrapper class for Account so I can mock active and inactive Accounts by changing the statecode and statuscode 
public class AccountWrapper : Account 
{ 
    // the member to store our "set statecode" values; only for use in testing and mocking 
    private AccountState? _statecode; 

    // override and replace the base class statecode 
    public new virtual AccountState? statecode 
    { 
     get { return _statecode; } 
     // this is how I intend to get around the read-only of this field in the base class 
     // the wrapper pretends to allow the statecode to be set, when it really does not stick on the actual Account entity 
     set { _statecode = value; } 
    } 
} 

И конкретный случай установки для организации службы издеваться, чтобы вернуть активный счет, когда Retrieve счета называется:

var activeAccountMock = new Mock<AccountWrapper>(); 
activeAccountMock.SetupGet(x => x.statecode).Returns(AccountState.Active); 
var serviceMock = new Mock<IOrganizationService>(); 
serviceMock.Setup(t => 
    t.Retrieve(It.Is<string>(s => s == Account.EntityLogicalName), 
       It.IsAny<Guid>(), // don't care about a specific Account 
       It.IsAny<ColumnSet>())) // don't care about a specific ColumnSet 
    .Returns(activeAccountMock.Object); 

Когда я осмотреть объект, возвращаемый методом service.Retrieve, он делает почти точно, что я хочу! Учетная запись типа Entity имеет statecode так, как я хочу, но в тот момент, когда предприятие преобразовано в Account, statecode возвращается к нулевому значению. Вероятно, это связано с тем, что преобразование вызывает конструктор учетной записи, который создает объект «Учетная запись» со всеми полями null, а затем устанавливает все поля, которые имеют общедоступный сеттер со значениями, доступными. В принципе, когда Учетная запись является поздней, это то, что я хочу почти, и когда она ранняя, я теряю значение своего состояния, которое я установил.

// this guy is type Entity, and its statecode is what I want! 
var accountLateBound = service.Retrieve(Account.EntityLogicalName, accountId, new ColumnSet(true)); 
// accountLateBound["statecode"] is AccountState.Active YAY! 
// this clobbers my glorious statecode mock... 
Account accountEarlyBound = accountLateBound.ToEntity<Account>(); 
// accountEarlyBound.statecode is null BOO! 

Мой код продукция использует ранние переплете объектов исключительно по уважительной причине - в основном развитие с ранней оценкой не отстой (Тары быть intellissense, компилятор проверяет, и т.д.). Я не хочу менять производственный код так, чтобы он лучше менялся с помощью Moq. Это и ранние сущности удивительны!

Я что-то не так с Moq?Нужно ли мне сосать его и использовать AccountWrapper в моем производственном коде? Должен ли я не конвертировать в раннюю границу в этом случае, чтобы я не потерял этот код состояния? Тогда мне пришлось бы изменить производственный код, чтобы смешивать поздний и ранний ... yuck. Я беспокоюсь об этом, поскольку оболочка дает идею, что вы можете установить код состояния объекта напрямую через account.statecode = AccountState.[Active|Inactive], а не использовать SetStateRequest. I это не так, комментариев объяснить это не так, но факт, что он выглядит, как вы можете, означает, что кто-то это сделает и ожидает, что он сработает.

Вся идея насмешки логики плагина была так, что мне не нужно было вообще обращаться к CRM! Я мог высмеивать все, что мне нужно было использовать. Когда блок тестирования логики плагинов, нет никаких причин, чтобы использовать реальные данные

Резиновая уточка уже нечестным надоело слушать меня ...

Т.Л., д-р - Могу ли я издеваться только для чтения statecode из раннего связанного объекта CRM, чтобы я мог выполнить единичный тест с объектами различных кодов состояний с использованием Moq и наследования/обертки/интерфейсы, если это необходимо? Если да, то как? Если нет, то почему?

+0

Т.Л., д-р я не могу говорить с конкретной методикой обновления или создания записи таким образом, но глубоко в моем нечеткой мозга я припоминаю, вы должны (или, может быть, он «должен») всегда устанавливается как statecode, так и statuscode одновременно, так как код состояния зависит от кода состояния (как подкатегория, эффективно), поэтому, обновляя вместе, вы избегаете проблемы их смещения – AdamV

+0

Интересно ... Я займусь этим. I_think_ существует только один конструктор для ранней привязки сущности, и он не принимает никаких параметров. – gfritz

ответ

4

Объекты Early Bound - это всего лишь обертка вокруг поздней границы. Попробуйте код ниже. В основном он устанавливает значение в коллекции атрибутов, с которой на самом деле читает базовая учетная запись. Он будет бомбить, если вы попытаетесь обновить или создать его в CRM, но если все локально, оно должно работать нормально.

// Wrapper class for Account so I can mock active and inactive Accounts by changing the statecode and statuscode 
public class AccountWrapper : Account 
{ 
    // the member to store our "set statecode" values; only for use in testing and mocking 
    private AccountState? _statecode; 

    // override and replace the base class statecode 
    public new virtual AccountState? statecode 
    { 
     get { return _statecode; } 
     // this is to get around the read-only of this field in the base class 
     // the wrapper pretends to allow the statecode to be set, when it really does not stick on the actual Account entity 
     set 
     { 
      _statecode = value; 
      if(value == null){ 
       if(this.Attributes.Contains("statecode")){ 
        this.Attributes.Remove("statecode") 
       } 
      } 
      else 
      { 
       this.SetAttributeValue("statecode", _statecode); 
      } 
     } 
    } 
} 
+0

Я вижу разницу между этой оберткой и той, которую я опубликовал. Я попробую это! – gfritz

+0

Вот и все! Используйте коллекцию атрибутов! – gfritz

+0

Я создал обширную платформу тестирования XRM, по-прежнему нужно добавить дополнительную документацию, но если вам интересно: https://github.com/daryllabar/XrmUnitTest – Daryl

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