2014-05-07 2 views
5

Ich möchte eine Instanz von FormsAuthenticationTicket erstellen (über die ich keine Kontrolle habe, Teil von System.Web.Security) mit Autofixtion und sicherstellen, dass die UserData (des Typen string) enthält einen gültigen XML-StringErstellen Sie eine Instanz von FormsAuthenticationTicket mit einer gültigen XML-Zeichenfolge in UserData

var testTicket = fixture.Create<FormsAuthenticationTicket>(); 

Das Problem ist, dass Userdata kann nur eingestellt werden, wenn das Objekt instanziieren den folgenden Konstruktor:

public FormsAuthenticationTicket(int version, string name, DateTime issueDate, DateTime expiration, bool isPersistent, string userData); 

Wo „userdata“ einen gültigen XML-String ist.

Ich kann diesen Typ konfigurieren, um den gierigsten Konstruktor zu verwenden, aber das löst nicht das Problem, eine gültige XML-Zeichenfolge für userData bereitzustellen.

Ich könnte den String-Typ einfrieren, damit es immer eine gültige XML-Zeichenfolge zurückgibt, aber ich interessiere mich auch für andere Zeichenfolge Werte in meinem Test.

Ich denke, ein möglicher Ansatz ist, den Algorithmus für die String-Generierung anzupassen ... aber ich habe keine Parameter zu wissen, wann die XML-ähnliche Zeichenfolge bereitzustellen.

Antwort

2

AutoFixture den bescheidenen Konstruktor nimmt (Standard) und da userData ist nicht Teil des bescheidenen Konstruktor brauchen wir zwei anpassen sachen hier:

  1. Ändern Sie die Konstruktorstrategie für einen einzelnen Typ (FormsAuthenticationTicket).
  2. Geben Sie einen benutzerdefinierten Wert für das Konstruktorargument userData ein.

die folgenden Anpassungs kapselt beide:

internal class UserDataCustomization : ICustomization 
{ 
    private readonly string userData; 

    public UserDataCustomization(string userData) 
    { 
     this.userData = userData; 
    } 

    public void Customize(IFixture fixture) 
    { 
     fixture.Customize<FormsAuthenticationTicket>(c => 
      c.FromFactory(
       new MethodInvoker(
        new GreedyConstructorQuery()))); 
     fixture.Customizations.Add(new UserDataBuilder(this.userData)); 
    } 

    private class UserDataBuilder : ISpecimenBuilder 
    { 
     private readonly string userData; 

     public UserDataBuilder(string userData) 
     { 
      this.userData = userData; 
     } 

     public object Create(object request, ISpecimenContext context) 
     { 
      var pi = request as ParameterInfo; 
      if (pi != null && pi.Name == "userData") 
       return this.userData; 

      return new NoSpecimen(); 
     } 
    } 
} 

Der folgende Test bestanden:

[Fact] 
public void UserDataIsCorrect() 
{ 
    var expected = "<foo></foo>"; 
    var fixture = new Fixture(); 
    fixture.Customize(new UserDataCustomization(expected)); 

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

    Assert.Equal(expected, actual.UserData); 
} 

Hoffnung, das hilft.


FWIW, hier ist auch das gleiche in F #:

open Ploeh.AutoFixture 
open Ploeh.AutoFixture.Kernel 
open System 
open System.Reflection 
open System.Web.Security 

type UserDataCustomization (userData) = 
    let builder = { 
     new ISpecimenBuilder with 
      member this.Create(request, context) = 
       match request with 
       | :? ParameterInfo as pi 
        when pi.Name = "userData" -> box userData 
       | _ -> NoSpecimen request |> box } 

    interface ICustomization with 
     member this.Customize fixture = 
      fixture.Customize<FormsAuthenticationTicket>(fun c -> 
       c.FromFactory(
        MethodInvoker(
         GreedyConstructorQuery())) :> ISpecimenBuilder) 
      fixture.Customizations.Add builder 

Der folgende Test bestanden:

open Xunit 
open Swensen.Unquote.Assertions 

[<Fact>] 
let UserDataIsCorrect() = 
    let expected = "<foo></foo>" 
    let fixture = Fixture().Customize(UserDataCustomization(expected)) 

    let actual = fixture.Create<FormsAuthenticationTicket>() 

    test <@ expected = actual.UserData @> 
2

Das Einfrieren der Zeichenfolge würde funktionieren, ist aber nicht wünschenswert, da dies auch alle anderen erzeugten Zeichenfolgen beeinflussen würde.

Ich benutze diese Klasse einen bestimmten Konstruktorargument anpassen:

public class GenericArgCustomization<T> : ISpecimenBuilder 
{ 
    private readonly string name; 
    private readonly T value; 

    public GenericArgCustomization(string name, T value) 
    { 
     if (String.IsNullOrEmpty(name)) 
      throw new ArgumentException("Name is required", "name"); 

     this.name = name; 
     this.value = value; 
    } 

    public object Create(object request, ISpecimenContext context) 
    { 
     var pi = request as ParameterInfo; 
     if (pi == null) 
      return new NoSpecimen(request); 

     if (pi.ParameterType != typeof(T) || pi.Name != this.name) 
      return new NoSpecimen(request); 

     return this.value; 
    } 
} 

Als nächst Sie es, indem Sie den generischen Typen (string in diesem Fall) verwenden können, und den Konstruktor Argument Namen, den Sie anpassen möchten (userData in diesem Fall). Dies unterscheidet Groß- und Kleinschreibung, daher entspricht es dem Argumentnamen, den Sie in der Klasse verwendet haben.

Beispiel:

var xml = "<root>My Valid XML Value Here</root>"; 
var customUserData = new GenericArgCustomization<string>("userData", xml); 
var fixture = new Fixture(); 
fixture.Customizations.Add(customUserData); 
var item = fixture.Create<FormsAuthenticationTicket>(); 

Jetzt wird das Element mit Daten erstellt, wie:

  • Version: 85
  • Namen: name1e8fb8b1-5879-4256-8729-ca6afeb1bd80
  • Issue: 12/3/2015 8:00:05 AM
  • IsPersistent: True
  • Userdata: <root>My Valid XML Value Here</root>
+1

Obwohl dies gut als generalisierte Ansatz suchen, ist es in diesem speziellen Fall wird nicht funktionieren, weil das 'userData' nicht Teil des bescheidenen Konstruktors ist. –

+0

@Nikos das ist fair, darauf hinzuweisen. Das erwähnte OP war mit der Einrichtung einer gierigen Konstruktor-Anpassung vertraut, also habe ich diesen Teil nicht nochmals betont. –

+1

Einverstanden. Aber ich persönlich bevorzuge autonome Antworten, bei denen Sie die Antwort einfach kopieren und einfügen und verwenden können. Benutzer lesen die Webseiten selten Wort für Wort; statt dessen [scannen sie die Seite] (http://www.nngroup.com/articles/how-users-read-on-the-web/). –