Search And Destroy

Look out honey, ’cause I’m using technology!

Archive for the ‘QuickNet’ Category

State of the Assemblies

Posted by kilfour on February 18, 2011

QuickGenerate :
Is coming along nicely.
Here’s the one of the latest tests f.i. (slightly modified) :

public class ReplacingPrimitiveGeneratorsTests
{
    private readonly DomainGenerator domainGenerator;

    public ReplacingPrimitiveGeneratorsTests()
    {
        domainGenerator =
            new DomainGenerator()
                .Entities(typeof(SomethingToGenerate))
                .With(42);
    }

    [Fact]
    public void Tadaaaaa()
    {
        Assert.Equal(42, domainGenerator.One<SomethingToGenerate>().SomeInt);
    }

    public class SomethingToGenerate
    {
        public int SomeInt { get; set; }
    }
}

It is already being used in production code quite extensively and as a consequence rapidly ‘growing up in public’.
An evolution I obviously fully support.

QuickDotNetCheck :
In end user computing apps, property based testing (these days) is rarely a good investement.
As that is what I have been writing lately, QuickDotNetCheck has not evolved.
I expect this to change in the near future though.

QuickNet :
Has been abandoned. No updates will be done and as soon as QuickDotNetCheck delivers, the QuickNet project will be deleted.

Posted in QuickDotNetCheck, QuickGenerate, QuickNet | Leave a Comment »

QuickDotNetCheck on Google Code

Posted by kilfour on January 5, 2011

Here.

It is a truly, _truly_ slimmed down version of quicknet.
Focus this time is on _usability_, whilst still keeping the QuickCheck principles working.

Posted in QuickDotNetCheck, QuickNet | Leave a Comment »

QuickDotNetCheck : Preview

Posted by kilfour on December 28, 2010

Considering :

public class ListDeleter
{
    public void DoingMyThing(IList<int> theList, int iNeedToBeRemoved)
    {
        theList.Remove(iNeedToBeRemoved);
    }            
}

We define the following Spec :
public class ListDeleterSpecs : ListDeleterFixture
{
    [Spec]
    public void List_Does_Not_Contain_Removed_Value()
    {
        Ensure.False(list.Contains(toRemove));
    }
}

And implement a QuickDotNetCheck Fixture :
public class ListDeleterFixture : Fixture
{
    private readonly ListDeleter listDeleter = new ListDeleter();
    private readonly IntGenerator intGen = new IntGenerator(1, 20);

    protected IList<int> list;
    protected int toRemove;

    public override void Arrange()
    {
        toRemove = intGen.GetRandomValue();

        list = 
            new GeneratorRepository()
                .With<int>(intGen)
                .Randoms<int>(1, 100)
                .ToList();
    }

    protected override void Act()
    {
        listDeleter.DoingMyThing(list, toRemove);
    }

    [Fact]
    public void VerifyAll() // Assert is already spoken for by BaseFixture
    {
        new Suite(1, 1000)
            .Register(() => new ListDeleterFixture())
            .Run();
    }
}

Resulting in something like :

  Falsifiable after 1 test(s), 375 Transition(s).
  ListDeleterSpecs.List_Does_Not_Contain_Removed_Value failed.
  --------------------Simplest Fail Case--------------------
  ListDeleterFixture
  theInt : System.Int32 : 52
  theList: List Of System.Int32 : 
      52
      52

Posted in Checking Stuff Out, QuickDotNetCheck, QuickNet | Leave a Comment »

On QuickNet 0.6

Posted by kilfour on September 23, 2010

It is drawing nearer.

The thing is, …
QuickNet 0.5 works for academic issues.
QuickNet in the trunk works for real world stuff, as in, it will verify the correctness of your program.
But one of the most important features, namely producing the ‘simplest possible fail case’, a.k.a. ‘Shrinking’, is broken.
Please note though that for anything more advanced than academic examples shrinking was failing in 0.5, as the Agatha tests quickly showed.

Earlier today I updated Agatha to use the latest QuickNet version.
It had been a while.
Mainly due to lack of a MSVS2010.

The decision to move the generators to a seperate assembly turned out to be a good one.

Unfortunately I took it one step too far, which is why shrinking is failing at the moment. Shrinking really needs to know all the other possible values that a generator can provide. Currently it only inspects the value and that just isn’t enough.

I need to retrace my steps, and reintroduce the Generator member of a transition.
And yes this means that you have to use QuickGenerate to generate your random stuff in order to use QuickNet. Despite previous statements that you could use any random data generator lib.

Don’t know how long this will take, but once it’s done, I’m calling it 0.6.

Posted in QuickGenerate, QuickNet | Leave a Comment »

QuickNet : State of the Assembly

Posted by kilfour on June 16, 2010

Honestly, … I haven’t used QuickNet in a while.

I’ve been involved with some new projects in the last couple of months.
All of them started out Test-Driven. So I’ve been putting my efforts into unit testing patterns more than in the property-based stuff.

The source in the trunk should be pretty stable though, and I reckon it is already a huge improvement over the 0.5 release.
And ofcourse the generators have undergone a serious face-lift.

The latter brings me to the reason why there isn’t any QuickNet.Generators.Example solution yet.

There are issues with the generators (most of which have been hacked around).
And everytime I sit down and think about a solution to any issue I have with the generators, the simplest thing that could possibly work seems to be Inversion of Control.

As I’ve stated previously I reckon IoC and currying, address the same problem. And although the implementations are vastly different, the solutions are similar.
Haskell’s QuickCheck generators work magically, out of the box, plugging in random values of the correct type in the functions under test. Currying ( amongst a lot of other things) makes this possible.
I’ve been trying to achieve the same ease of use.
The code however, is not getting any prettier with each corner-case I discover, or each feature added.

And everytime I sit down and think about a solution to all this, the simplest thing that could possibly work seems to be Inversion of Control.

Also, …
I’m moving house, my dog died, I lost my drivers license, my girlfriend wants to have a sex-change operation, I’m stuck in rehab, my boss asked me to develop the DoomsDay.Device.Core library, I have to get my car fixed, I’m inbetween jobs,… excuses, excuses, ….

I do need to get my hands on a VS2010 urgently though, as Agatha has already migrated, and I haven’t been able to update the (last-time-I-looked) flawed QN-tests.

And as the Agatha community has been contributing features and accompanying unit tests, I am anxious in seeing how I could translate this into QN-tests… and hopefully uncover a bug or two ;-)

Posted in Agatha, QuickNet | Leave a Comment »

QuickNet.Generators : Composing Composites

Posted by kilfour on April 22, 2010

Consider the following small model :

public class Product
{
    public long Id { get; set; }
    public int Amount { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
    public double NettoPrice { get; set; }
    public Company Supplier { get; set; }
}

public class Company
{
    public long Id { get; set; }
    public Person Contact { get; set; }
    public Address Location { get; set; }
}

public class Person
{
    public long Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public Address Residence { get; set; }
}

public class Address
{
    public string City { get; set; }
    public string PostalCode { get; set; }
    public string Street { get; set; }
    public int HouseNumber { get; set; }
}

Then using the GeneratorRepository like so :
new GeneratorRepository()
    .Random<Product>();

Returns f.i. :
{Product}
Int64 Id = 96
Int32 Amount = 43
String Description = m[wt`t\`f\g\u]vxugrg\\fdta
Double Price = 53,4536713443015
Double NettoPrice = 32,9169867219948
Company Supplier =
    null

Composing the Random Value
Revisiting the RepositoryGenerator’s With method, we use it to inform the repository of the other classes that are needed for generation :

new GeneratorRepository()
    .With<Address>()
    .With<Person>()
    .With<Company>()
    .Random<Product>();

And we get f.i. :
{Product}
Int64 Id = 21
Int32 Amount = 85
String Description = rtywrzZmr[]f
Double Price = 16,9683141712883
Double NettoPrice = 79,5729548519351
Company Supplier =
    Int64 Id = 6
    Person Contact =
        Int64 Id = 56
        String FirstName = kuxwqlgsok^sd`c`ucz]\ouzi]xvpp`fhZmgxd[al^\hvtguu`ej\iwvzxhmok]
        String LastName = esecnvbkbrlylg]op\[idpcz^qgZvhlZ[]\]i^ayxubdxyclttxmjnopje_wib
        Address Residence =
            String City = t`kwieZ_lu\kihy[_gu`\kzjhhgn^ydjp`h^f[tat
            String PostalCode = erh\`bkdzjn\lc`[i[xg[mklvczto^mnfi_a[ea
            String Street = \tzuvnn_xe
            Int32 HouseNumber = 56
    Address Location =
        String City = cglsavawbqovwZp]]yz^tsdampqbotvdludzwfZ`^ewe_^xu
        String PostalCode = k[yfhyk\d_k_ybived[qp`rytziwz\irvd^rwx]wtxl`i[_\gjutw^bddZl
        String Street = in]bqsco]qyg`_xsokisufiibovr\
        Int32 HouseNumber = 83

Ignoring properties
In case we would like the id properties of the classes to be ignored we could define it specifically for every type :

new GeneratorRepository()
    .With<Address>()
    .With<Person>(gen => gen.Ignore(val => val.Id))
    .With<Company>(gen => gen.Ignore(val => val.Id))
    .Random<Product>(gen => gen.Ignore(val => val.Id));

Or we could use a With convention that uses the name of the property.
new GeneratorRepository()
    .With<long>(mi=> mi.Name == "Id", val => 0)
    .With<Address>()
    .With<Person>()
    .With<Company>()
    .Random<Product>();

‘mi’ stands for MemberInfo, so for each property generated of type long and of which the Name equals Id, we generate a zero.

Both giving the same result :

{Product}
Int64 Id = 0
Int32 Amount = 67
String Description = ldl_hifv
Double Price = 40,0705830343396
Double NettoPrice = 85,4157260276451
Company Supplier =
    Int64 Id = 0
    Person Contact =
        Int64 Id = 0
        String FirstName = ]e\q]trnkqu]alb\qhpx[^
        String LastName = muhsmjyv[zj
        Address Residence =
            String City = ^]u`jxk[
            String PostalCode = r[`x]tpgnecy^ivpZ_]lut^rh^zwa_zk]lvsavi
            String Street = bhgna_znykjsgjsyxiizut`ifsvmn]h^pgcgfkjc_eyp
            Int32 HouseNumber = 64
    Address Location =
        String City = ]ntwusgjvibyb
        String PostalCode = cfzu]f\z`flgy`tiuju_obtqbor`
        String Street = t^hb\zsf]lb^^ggdhu`pfor]\tZmbmiowhf
        Int32 HouseNumber = 22

More conventions : Formatting sample
What if we would like our generated doubles that are named like price to be rounded :
new GeneratorRepository()
    .With<double>(mi => mi.Name.ToLower().Contains("price"),
                  val => Math.Round(val, 2))
    .Random<Product>();

Gives us f.i. :
Int64 Id = 87;
Int32 Amount = 10;
String Description = onqpc`^g`nwysvuhadckub_^ddhgd[]p[hwhdtnxiilmvnvd^qihmm[fi;
Double Price = 57,37;
Double NettoPrice = 34,69;
Company Supplier =
    null

Ofcourse in our case, the precondition is valid for both doubles, so let’s just drop it :

new GeneratorRepository()
    .With<double>(val => Math.Round(val, 2))
    .Random<Product>();

Gives a similar result.

Posted in QuickGenerate, QuickNet | 2 Comments »

QuickNet.Generators : Composite Values

Posted by kilfour on April 15, 2010

Consider the following class :

public class Product
{
    public long Id { get; set; }
    public int Amount { get; set; }
    public string Description { get; set; }
    public double Price { get; set; }
    public double NettoPrice { get; set; }
}

In order to get a random Product we use the GeneratorRepository, like so :
new GeneratorRepository().Random<Product>();

Which results in, f.i. :
{Product}
Id: 27
Amount: 91
Description: fpxyz]`Zizkl[w^rjlfv_la``udzh\eqx
Price: 3,22374686003837
NettoPrice: 8,77635564225556

The GeneratorRepository uses the primitive generators, to construct a composite value. These primitive generators are initialized using default values. The DoubleGenerator and IntGenerator f.i. both initially supply values between -1 and 100.

Now for some manipulations.

Ignoring properties
There exists an overload of the Random method which hands you the Generator so that you can customize things.

new GeneratorRepository()
    .Random<Product>(
    gen =>
    gen.Ignore(product => product.Id));

Id will now not be generated.
{Product}
Id: 0
Amount: 96
Description: ^`_iwmoyZatwnq_nzfwhZdbxrZhd`wkpprzb`khliczpth`xoqZ
Price: 7,06006666881035
NettoPrice: 89,0840827566963

Defining a specific generator for a specific property
Using the same overloaded method :

new GeneratorRepository()
    .Random<Product>(
    gen =>
    gen.For(product => product.Amount, new IntGenerator(5, 10)));

The Amount property will now be in the range of (5,10) instead of in the default range of (-1,100).
{Product}
Id: 52
Amount: 7
Description: uqsgpnwz]ipfcl[`oxsnk[
Price: 6,75318720180224
NettoPrice: 41,2337315954425

Changing the Generator per type
Introducing the ‘With’ method, which has a number of overloads. Below is the simplest form of usage.

new GeneratorRepository()
    .With<double>(gen => new DoubleGenerator(1,2))
    .Random<Product>();

Both the Price and NettoPrice property will now be in the range of (1,2) instead of in the default range of (-1,100).
{Product}
Id: 54
Amount: 86
Description: fuyikdtff\ZeodZimgpr]yildwg\q`jahiffb]\svyrpZaZ
Price: 1,75700874708454
NettoPrice: 1,46206869998112

Next up : Composite/Composite values and more manipulating.

Posted in QuickGenerate, QuickNet | Leave a Comment »

QuickNet.Generators : Primitives

Posted by kilfour on April 15, 2010

This is the first post in a small series, touring the QuickNet.Generators lib,

Let’s have a look at generating simple things : ‘primitives’.

QuickNet.Generators contains a number of predefined PrimitiveGenerators.
F.i. the IntGenerator :

var generator = new IntGenerator(-5, 5);
for(int i = 0; i < 5; i++)
{
    Console.Write(generator.GetRandomValue());
    Console.Write(";");
}

Could produce : ‘-1;4;3;-3;0;’
Or the BoolGenerator :
var generator = new BoolGenerator();
for(int i = 0; i < 5; i++)
{
    Console.Write(generator.GetRandomValue());
    Console.Write(";");
}

Could produce : ‘false;true;false;true;true;’

QuickNet.Generators contains a number of primitive generators :

  • BoolGenerator
  • CharGenerator
  • DateTimeGenerator
  • DecimalGenerator
  • IntGenerator
  • LongGenerator
  • StringGenerator

Apart from generating random values the PrimitiveGenerators are the end nodes in a QuickNet.Generators random value, which can be a composed value. The PrimitiveGenerators are the leafs in this composite structure, as will be shown in the next post.

Next up : Composite Values.

Posted in QuickGenerate, QuickNet | Leave a Comment »

QuickUpdate

Posted by kilfour on April 12, 2010

So far … backwards compatible…

I’ve been coding quite a bit of undocumented features into QuickNet…

Including a Vial class which an Alchemist can use in order to put together an AcidTest.

As one might deduce from above sentence, some stuff needs some explaining.

I wanted to slow things down, and clean up the stuff that _really_ works first, tackling the trickier issues at a later date.

Hence the idea to split of the generators in a different assembly.

These can be quite usefull even without QuickNet. I use them succesfully f.i. to test my data layer, generating random entities that need to be persisted. I can imagine more than one scenario (especially in testing though) where they might save quite a bit of work.

And the interface is pretty much stable.
Collection generation still needs to be looked at. For now there’s only a ListGenerator and the interface ain’t very pretty.

So I have started to seperate the generators from the rest of quicknet.
This has led to a number of positive evolutions. The code is slowly becoming cleaner. Although taking the ‘Shrinking’ capabilities out of the generators has led to an ugly ShrinkingStrategyFactory class, overall the effect is positive. The need for deep cloning of the generators has been removed for one, as have a lot of incomprehensible casts.

I also started writing some better tests for the new QuickNet.Generators assembly. Adhering to the dogfood principle I’m using quicknet to test the QuickNet.Generators.

There will be a QuickNet.Generators 0.6 release pretty soon.
I’m going to be posting some examples and questions on the mailing list, any suggestion will be taken into account.

Shrinking (in QuickNet, not QuickNet.Generators) is broken in the trunk (*) and will remain partially broken untill the way collections are generated is fully determined.
On the upside I will supply an example of usage project for the generators, which shows how to test your nhibernate CRUD operations in a very concise way, and I’m thinking about a ‘populate the database with a bunch of random data’ example. Although the latter might have to wait.

(*) To tell you the truth, it does not really work well in QuickNet 0.5 either. I’m treating it as legacy code, refactoring it, rewriting it, this time ’round using tests though …

Posted in QuickNet | Leave a Comment »

Our Heads Unmoved

Posted by kilfour on March 23, 2010

Here’s a typical challenge one faces when writing tests for quicknet itself.
A simple one, testing a generator.

This is the code I want to test :

public class IntGenerator : BasePrimitiveGenerator<int>
{
    private readonly int min;
    private readonly int max;

    public IntGenerator() : this(-1, 100) { }

    public IntGenerator(int minValue, int maxValue) { min = minValue; max = maxValue; }

    protected override int RandomValue()
    {
        return Seed.Random.Next(min, max);
    }
}

What I want in tests :

  • Construction never throws an exception.
  • When calling GetRandomValue :
    • If Max constructor parameter was smaller than Min constructor parameter GetRandomValue throws an exception.
    • Return value is greather than or equal to Min constructor parameter.
    • Return value is equal to Min constructor parameter sometimes.
    • Return value is smaller than Max.
    • Return value equals to Min _and_ Max If Min constructor parameter equals Max constructor parameter.

The random result of the method makes writing unit tests for this pretty hard. As they might pass sometimes, but fail after running them a couple of times.
Also asserting that GetRandomValue returns the Min value _sometimes_, seems pretty tricky.

Here’s the quicknet test :

public class IntGeneratorTestState : AbstractState
{
    public int Min { get; set; }
    public int Max { get; set; }
    public IntGenerator Generator { get; set; }
}

public class CreateIntGeneratorTransition
    : MetaTransition<Tuple<int, int>, IntGenerator, IntGeneratorTestState>
{
    public CreateIntGeneratorTransition(IntGeneratorTestState state)
        : base(state)
    {
        Execute = input => new IntGenerator(input.First, input.Second);
    }
}

public class IntGeneratorGetRandomValueTransition
    : MetaTransition<Null, int, IntGeneratorTestState>
{
    public IntGeneratorGetRandomValueTransition(IntGeneratorTestState state)
        : base(state)
    {
        Precondition = () => State.Generator != null;
        Execute = input => State.Generator.GetRandomValue();
    }
}

public class IntGeneratorSpecs : AcidTest<IntGeneratorTestState>
{
    public IntGeneratorSpecs()
        : base(50, 20)
    {
        GeneratorMap.SetGenerators(
            new IntGenerator(-1, 1),
            new IntGenerator(1, 1),
            new IntGenerator(1, 100000));

        GeneratorMap.SetGenerator<Tuple<int, int>>();
    }

    [SpecFor(typeof(CreateIntGeneratorTransition))]
    public Spec NoExceptionEver(Tuple<int, int> input, IntGenerator output)
    {
        return new Spec(() => Ensure.NotNull(output))
            .WhenHolds(
            () =>
            {
                State.Min = input.First;
                State.Max = input.Second;
                State.Generator = output;
            });
    }

    [SpecFor(typeof(IntGeneratorGetRandomValueTransition))]
    public Spec MaxSmallerThanMinThrows(Null input, int output)
    {
        return
            new Spec()
                .If(() => State.Max < State.Min)
                .Throws<ArgumentOutOfRangeException>();
    }

    [SpecFor(typeof(IntGeneratorGetRandomValueTransition))]
    public Spec OutputIsGreatherThanOrEqualToMin(Null input, int output)
    {
        return
            new Spec(() => Ensure.True(State.Min <= output))
                .If(() => State.Max > State.Min);
    }

    [SpecFor(typeof(IntGeneratorGetRandomValueTransition))]
    public Spec OutputIsMinSometimes(Null input, int output)
    {
        return
            new Spec()
                .If(() => State.Max > State.Min)
                .IfAfter(() => output == State.Min);
    }

    [SpecFor(typeof(IntGeneratorGetRandomValueTransition))]
    public Spec OutputIsSmallerThanMax(Null input, int output)
    {
        return
            new Spec(() => Ensure.True(State.Max > output))
                .If(() => State.Max > State.Min);
    }

    [SpecFor(typeof(IntGeneratorGetRandomValueTransition))]
    public Spec OutputEqualsToMinAndMaxIfMinIsMax(Null input, int output)
    {
        return
            new Spec(() => Ensure.True(State.Max == output))
                .If(() => State.Max == State.Min);
    }
}

Posted in QuickNet | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.