www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Mocking framework

reply simendsjo <simen.endsjo pandavre.com> writes:
Are there any mocking frameworks that actually works for D2?
And what is possible to mock, and what not?

My guess is only classes and interfaces can be mocked.
And only non-final classes and non-final methods.
Is this correct?
Mar 07 2011
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, March 07, 2011 01:46:36 simendsjo wrote:
 Are there any mocking frameworks that actually works for D2?
 And what is possible to mock, and what not?
 
 My guess is only classes and interfaces can be mocked.
 And only non-final classes and non-final methods.
 Is this correct?

There's nothing official that does that sort of thing. There _might_ be a third party library out there (dsource.org would be the place to check, I guess), but most 3rd party D libraries (of any variety) are D1 rather than D2 (though there _are_ some which are D2). I'd be surprised if such a library exists, but maybe it does. But if you're mocking up objects by deriving from them, then you're definitely not going to be able to override anything which is final, and if the whole class is final, then deriving from it will be impossible too. However, it _is_ very common to use structs instead of classes unless you actually need polymorphism, so it's quite common, and you can't override structs at all (though you could wrap them, and a lot of templated code would work with a wrapped struct as well as the original - but that depends on the template), so I'm not sure how much mileage the you'd get out of mock objects in D in general. Then again, I've never used a library for mock objects and have used hand-written ones rather rarely anyway, so I don't know that much about what you'd want to use them for. - Jonathan M Davis
Mar 07 2011
parent reply simendsjo <simen.endsjo pandavre.com> writes:
I gave this some thought, and I'm probably just a bit braindamaged by C#.
Consider you wish to unittest a class that fetches data from a database and
sends an
email.
The common scenario here is to use IoC and mock the objects so you can check
that
"FetchData" was called and "SendEmail" is called using the data from your
"FetchData".

So this is the scenario:

interface SomeBigInterface {
    void doStuff();
    // And many more methods here
}

class SomeClassImplementingInterface : SomeBigInterface {
    void doStuff() {}
    // And many more methods here
}

class SomeClass {
    SomeBigInterface _i;
    this(SomeBigInterface i) {
        _i = i;
    }

    void someComplexStuff() {
        _i.doStuff();
    }
}

And how can I mock the entire SomeBigInterface containing 20 methods just to
make sure
doStuff is called? And what if it didn't take an interface, but an SmtpClient?

But then I thought I might be forcing D into the limitations of C# and other
pure oo
langauges.
Then I created this instead:

// Now I'm only depending on the methods I use, not an entire interface or a
specific
class/struct
class SomeClass2(T)
    if( is(typeof({ return T.init.doStuff(); })) )
{
    T _i;
    this(T i) {
        _i = i;
    }

    void someComplexStuff() {
        _i.doStuff();
    }
}

Then I can mock it up a lot easier:

    class MyMock {
        int called;
        void doStuff() { ++called; }
    }

    auto mock = new MyMock();

    auto a = new SomeClass2!MyMock(mock);
    assert(mock.called == 0);
    a.someComplexStuff();
    assert(mock.called == 1);
    a.someComplexStuff();
    assert(mock.called == 2);


And voila.. It's simpler to create the mock object by hand than through a
library.
The question is, is this good practice? Should I often just create templates
like
isSomeInterface (like the range api does) checking for methods and properties
instead of
using interfaces directly?
Mar 09 2011
parent simendsjo <simen.endsjo pandavre.com> writes:
I should correct myself a bit... By putting the if on the class level
I need to add every method used by the class, and also add all these
methods to the mock object. It should be added to the method level
where doStuff() is called.
Mar 09 2011