What you need is a "mocking" framework. Essentially the mocking framework will intercept certain calls and substitute some other value/object. In your example you could mock the half dozen steps and then test only the bit of code you actually want to exercise.
Take a look at the following for some further info:
http://www.nermins.net/post/2007/04/TDDUsing-Mock-objects-with-CSLANet.aspx
Hi
nermins.net url is not working , kindly please share the updated link for TDD with csla
An excellent question. And this has been the only big issue
with Csla, or any tightly integrated system. On one hand you gain so much
– if you take a look at the architecture of an Enterprise System built on
Csla, and comparably sized one built on another technology, you will see that
ones built on Csla are by far simpler.
But that tight integration results in complications when it
comes to Unit testing. But before I get to the point of what is the
problem in testing scenarios in Csla, let me take a bit longer route explaining
how is isolating of objects being Unit tested done.
When you unit test your JobSchedules BO, you need to mock calls
to some of the objects that it depends on, and just assure that internally JobSchedules
is calling the methods with expected parameters. Those would be your
mocks. In some other dependencies in order to test the functionality
inside JobSchedule, dependency object needs to return a pre-packaged set of values
in order for your tests on JobSchedule to run.
For example each job might have a list of materials, that the
job is calculating the total cost for. Since the iteration, and the
calculation is run on the Job object, you need that pre-packaged set from
MaterialList BO without running the full MaterialList BO (it executing its own
internal methods that like you said can fail for other reasons, then having
perhaps other dependencies like database, etc). So in order to avoid that
type of dependency you create what is called a Stub. Stubbing MaterialList
would mean again replacing the actual object with a Stub one that when you
call, lets say GetListOfItemsAndPrices() methods on it returns a pre-packaged
response that the JobSchedules BO can use in its test.
Now since I mentioned two types of Fake objects that helps us
isolate our unit of testing (JobSchedules in this case), for different cases,
the question becomes how does one create Mocks and Stubs.
There are 2 ways:
-
Static Mocks and Stubs
-
Dynamic Mocks and Stubs
Static ones are created by subclassing – in order to
create a MaterialList Stub, you create an object that inherits from it, then
override the GetListOfItemsAndPrices() to return the set of data needed for
your test.
For static Mocks, you generally tests situations like if a
certain condition is met on JobSchedules then we call method A() on Material BO
dependency, or if condition fails, you call method B(). Solution again is
subclassing, overriding methods A() and B() to do nothing other than increasing
a counter properties like ACalledNTimes, or BCalledNTimes which are also
defined on you static mock object that subclasses Material BO for example.
The problem with static Mocks and stubs is that they result in a
lot of code. Lets go to MaterialListStub, and GetListOfItemsAndPrices().
What if I want to test how JobSchedules responds to several different
scenarios, in other words one scenario where GetListOfItemsAndPrices() returns several
valid items and prices, and then second one where prices are missing on some of
the elements, or third where the GetListOfItemsAndPrices() perhaps throws some
sort of exception, perhaps FormatException (you still want to test that the
code inside your Unit being tested handles the expected exceptions from
dependencies).
For each of those 3 cases you have to create another Subclass,
which returns one of the expectations for GetListOfItemsAndPrices(). That
is a lot of code. This is the reason people came up with dynamic Mock and
Stub frameworks. With this you just say:
1)
I want to create a stub of object MaterialList
2)
When called GetListOfItemsAndPrices() replace its return value
with “this object”.
3)
Inject the Stub of MaterialList instead of actual object into
JobSchedules
4)
Call the JobSchedules method you are testing
5)
Run your assertions
Now lets take a look how would that look in a code of our test:
//Arrange
var fakeItemsPrices = new Dictionary<Item,Price>(){ new…,
new…, …};
var materialList = MockRepository.GenerateStub<MaterialList>();
materialList.Stub(f => f. GetListOfItemsAndPrices ()).Return(fakeItemsPrices);
//Action
var jobSchedules = new JobSchedules(MaterialList);
var result = jobSchedules.ActionTested();//this is where the
call to GetListOfItemsAndPrices() occurs
//Assert
Assert.AreEqual(Expected_Value, result….)
Which finally brings me to a problem in testing scenario in
Csla. HOW DOES ONE INJECT THESE FAKE OBJECTS (STUBS AND MOCKS) during the
tests and replaces the actual Csla BO dependencies for JobSchedules?
In order for that to happen – in general, outside Csla,
people use what is called a Dependency Injection pattern. They create
constructor overloads where they pass as parameters references to all dependencies
their object interacts with. So what that means is that JobSchedule would
have a 2 constructors:
private JobSchedule() : this (new MaterialList()){
}
Public JobSchedule(MaterialList materialList){
this. materialList = materialList;
}
As you can see all the first constructor does is – it calls
the second one passing it a new instance of the MaterialList. Second
constructor then “injects” that referenc into internal field to be
used for later. But second constructor is also key for our tests, as suring
the tests we can pass Static/Dynamic Mock of MaterialList instead of the actual
object, as seen in following 2 lines of the example above:
var materialList = MockRepository.GenerateStub<MaterialList>();
…
var jobSchedules = new JobSchedules(MaterialList);
BUT THAT EXAMPLE WILL NOT WORK ON CSLA! Why? CSLA BOs are
Mobile Objects, they live in multiple contexts, and are generally created in Server
Context, not client context. That means – we do not call
constructors directly (and that is the reason why constructor are generally private).
Object is constructed on the server and then serialized back to the
client. We also generally use Factory Methods to get instances of our
Csla BOs.
So how does one “INJECT” dependency into Csla BOs
during tests. One solution (which will cost you) is to use
TypeMock/Isolator dynamic mocking framework. There are 3 bing names in
Dynamic Mocking frameworks in .Net: Example above was using RhinMocks 3.5 (by
far the most popular Mocking framework in .Net). Then there is a newcomer
Moq which works only on .Net 3.5, and already mentioned TypeMock (renamed to
Isolator in version 4.2). RhinoMocks and Moq can only work in scenarios
where Dependencies are injected directly into constructor, or perhaps property
sets before one calls method being tested.
TypeMock/Isolator does not need that. You can state replace this
object, and a call on its method with this value (which will happen later in
the test) without having an access to the reference that you need to
mock. In other words, MaterialList can be constructed completely
internally in JobSchedule object with no outside visibility, and you can still
replace the actual MaterialList instance with your Dynamic Mock/Stub.
How? TypeMock, unlike other dynamic mocking frameworks
uses Profiler API, allowing it to replace the actual objects/calls during
runtime. You do not need to touch your code in order to make it “testable”.
So the example test from above remains the same except that instead of calling
this line to create your jobSchedule:
var jobSchedules = new JobSchedules(MaterialList);
is replaced with Csla standard Factory Method (constructed the
same way as when you use it in code):
var jobSchedules = new JobSchedules.CreateNew();
The problem with the TypeMock/Isolator is that it will cost you
(few hundred per developer). There was a free community version that is
powerful enough for these types of tests (which I used few years back), but
they changed it recently so that after 30 days it throws very annoying popups
after each test run.
So I gave up on TypeMock/Isolator, for RhinoMocks. And
when I construct my objects, I try to make dependencies “Lazy Loaded”,
something like, lets say that the MaterialList is exposed as Property on
JobSchedules, like:
public MaterialList Materials{
get{
if(_materials==null) _materials =
LoadMaterials();
return _materials;
}
set{ _materials = value}
}
Then in my test I can set the Materials Property to a value of
my Mock MaterialList, prior to running test method. Sometimes that is
impossible (performance might dictate minimizing round-trips to the server, or
something of that sort so all dependencies/children are loaded inside root Fetch),
and the only solution is to create a public overload of the constructor on the JobSchedule.
Problem with that is that then if your test constructs the object by
calling a constructor overload and the runtime uses FactoryMethods, we might
miss some of the initializations performed inside Factory Method, and
DataPortal_XYZ.
Due to that in this upcoming version of Csla.Net we are coming up
with a concept of ObjectFactory, which will allow us to route calls on:
DataPortal.Create<JobSchedule>() to our own Factory that
determines what gets called during construction (including DataPortal_XYZ)
methods. With getting that level of control, we actually get the ability
to replace the behavior inside the DataPortal_XYZ, and mock dependencies
constructed there.
We are working on this right now, so please stay tuned and
follow both of our blogs for examples of unit tests on that implement
ObjectFactory. My blog is at www.nermins.net,
and you will find some of the (older) examples of the dynamic mocking using TypeMock.
Some of the new examples will utilize the ObjectFactory and will be a part of Csla
MVC demo (source of which can be already found on my most recent blog post).
Nermin
From: Pawz
[mailto:cslanet@lhotka.net]
Sent: Tuesday, September 09, 2008 7:44 PM
To: Nermin Dibek
Subject: [CSLA .NET] Unit Testing & CSLA
Hi all,
I've got a question about setting up unit tests for business objects that
depend on certain other objects having done their job.
Basically, I've got a JobSchedules BO that I want to test to make sure it's
loading up upcoming jobs that need to be manufactured, but in order for a job
to be ready for manufacture, there's about half a dozen steps that need to be
performed for each job. What's the best way to do this kind of thing? I'm
heading down the route of just calling all the business objects in order to set
up the job correctly, but I'm a bit worried that if there's a problem with an
unrelated BO, this test will fail (ie, if the Materials BO fails, the job may
never get ordered, which means it doesn't show up to be scheduled, which means
if I test to make sure it's showing up in the Scheduler BO, that test will fail
as well, without any clear indication of why). Worst case would be like a top
end BO failing (no Job at all!) and like 100 tests go red.
On the other hand, I wouldn't want to script it out either, because I need to
know that all appropriate business logic has been applied at all stages. I'm
still new to this Test Driven type stuff, so maybe I'm just missing something
simple?
Keep in mind that there are two ways to look at your code when developing unit tests - and both are just a valid and I highly recommend implementing both.
The first and simplest are "black box" tests. When you create a black box test, you are testing the functionality of a piece of code with no regard for how or what it's doing internally to accomplish the task. An example is calling a service method and evaluating the response. This can be done at the BO level as well to ensure that things are done correctly. These tests are great for regression and integration testing later on as well.
However, to be thorough, you need to test how the behavior is implemented. This is typically referred to as "white box" testing (I've heard the term "smoke testing" on occassion, too). The trick here is to evaluate every possible path through your code, including error conditions, to make sure that the code handles every scenario correctly. So, if you are examining a method that has limits on values for a specific parameter, your test should call it with a legitimate value AND values that should make the method fail. If the code behaves one way versus another depending on some object's state, then you need to run the test using every possible state to ensure that the code executes properly.
When using the mock approach described so thoroughly above, keep this in mind and realize that you might have to have multiple mocks in order to fully test your code. It can get complicated, but the great thing about code-based testing is that it only has to be written once!!!
HTH
Copyright (c) Marimer LLC