Newbie wants to take some JUnit group. Some basic questions.

View: New views
7 Messages — Rating Filter:   Alert me  

Newbie wants to take some JUnit group. Some basic questions.

by Serethos :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hello!

I am an quite experienced programmer but new to the philosophy of unit
testing. An issue I want to change.
I read some articles and took some orientation on Frank Westphal's
very good book about that topic. But in practice, I always run into
similar problems, which seem to disturb my view of unit testing. So
some thought and questions I would like to discuss.

1. Recently I read that a unit test is no one if you have to touch
network, db or filesystem. I understand the point that these accesses
really can slow the tests down and usually need extra work of
configuration, but how to avoid this?
An example of my daily work. I have quite a common task: Fetch some
xmls from an ftp server, parse the content and map it into db and vice
versa. So the business logic is quite thin. More important is good
exception handling and the transport of all data in the right structures.

Actually the slowdown of a real ftp transport and the configuration
and injection overhead of the db-connection is a major drawback. But
on the other hand I see no good way to mock the behaviour of these
endpoints.
I could try to mock a database, but how to test, if an sql-statement
is correct (especially for a wider range of queries)?
It also is a very hard work to write stubs or mocks, which can answer
with all error-states an ftp-server/network can generate (timeout,
access denied, authentication etc) to test the correct error handling
of my code.

2. Another question points to a basic principle of unit testing: the
opening of a class in small and public methods. I see an advantage in
the possibility to inject every aspect of a class (manually or e.g.
via spring) and the code can benefit from a better readability through
a chain of self-explanatory method calls.
But in some cases I want to hide implementation details from the user.
Taking my Importer/Exporter example a second time, it is more a cron
script than an application: Doing a defined job in a robust and
understandable manner but neither designed as a basis for wide
enhancements nor for ultimate flexibility.
So there are methods which start the whole work of an importer over
the whole lifecycle (connect, fetch data, map data etc). Methods,
which are necessary for getting the object in a usable state (e.g.
connection established) are hidden away. To ensure that there must be
the correct state before executing the main task I can lead the user
with parameterized constructors (e.g. MyImporter(host, port)).
To say it more generally I think that it is a common way to restrict
the use of classes which need to be handled in correct order because
of their state. This saves a lot of additional exception handling
(e.g. executing before connecting).
But following this thought it gets very hard to isolate testing units.
Even when I separate the tasks within the class to units (connecting,
disconnecting etc) they would be not accessible and would need to be
tested from within.

This is only a very simple and not a perfect example but I think my
point should be clear. I hope that some of you take some time to read
it. I really would appreciate some thoughts!


Re: Newbie wants to take some JUnit group. Some basic questions.

by jayasinghe :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi!

Looking at your email-address I assume that you are german. ;-) So, if you are motivated
to read more about JUnit and TDD check out the just released 2nd edition of "Softwaretests
mit JUnit" by Johannes Link. It cotains a larger chapter about mocking and working
distributed systems.

Regarding your SQL queries it might be a trade-off to use a slim in memory-database to
validate whether your SQL queries are correct. However you might not be able to simulate
your production-database since it might interpret your SQL slightly different..  

Best Regards,
Robin

--- In junit@..., "serethos_0" <Serethos@...> wrote:

>
> Hello!
>
> I am an quite experienced programmer but new to the philosophy of unit
> testing. An issue I want to change.
> I read some articles and took some orientation on Frank Westphal's
> very good book about that topic. But in practice, I always run into
> similar problems, which seem to disturb my view of unit testing. So
> some thought and questions I would like to discuss.
>
> 1. Recently I read that a unit test is no one if you have to touch
> network, db or filesystem. I understand the point that these accesses
> really can slow the tests down and usually need extra work of
> configuration, but how to avoid this?
> An example of my daily work. I have quite a common task: Fetch some
> xmls from an ftp server, parse the content and map it into db and vice
> versa. So the business logic is quite thin. More important is good
> exception handling and the transport of all data in the right structures.
>
> Actually the slowdown of a real ftp transport and the configuration
> and injection overhead of the db-connection is a major drawback. But
> on the other hand I see no good way to mock the behaviour of these
> endpoints.
> I could try to mock a database, but how to test, if an sql-statement
> is correct (especially for a wider range of queries)?
> It also is a very hard work to write stubs or mocks, which can answer
> with all error-states an ftp-server/network can generate (timeout,
> access denied, authentication etc) to test the correct error handling
> of my code.
>
> 2. Another question points to a basic principle of unit testing: the
> opening of a class in small and public methods. I see an advantage in
> the possibility to inject every aspect of a class (manually or e.g.
> via spring) and the code can benefit from a better readability through
> a chain of self-explanatory method calls.
> But in some cases I want to hide implementation details from the user.
> Taking my Importer/Exporter example a second time, it is more a cron
> script than an application: Doing a defined job in a robust and
> understandable manner but neither designed as a basis for wide
> enhancements nor for ultimate flexibility.
> So there are methods which start the whole work of an importer over
> the whole lifecycle (connect, fetch data, map data etc). Methods,
> which are necessary for getting the object in a usable state (e.g.
> connection established) are hidden away. To ensure that there must be
> the correct state before executing the main task I can lead the user
> with parameterized constructors (e.g. MyImporter(host, port)).
> To say it more generally I think that it is a common way to restrict
> the use of classes which need to be handled in correct order because
> of their state. This saves a lot of additional exception handling
> (e.g. executing before connecting).
> But following this thought it gets very hard to isolate testing units.
> Even when I separate the tasks within the class to units (connecting,
> disconnecting etc) they would be not accessible and would need to be
> tested from within.
>
> This is only a very simple and not a perfect example but I think my
> point should be clear. I hope that some of you take some time to read
> it. I really would appreciate some thoughts!
>


Re: Newbie wants to take some JUnit group. Some basic questions.

by Joakim Ohlrogge :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

The problems you describe are problems that are common to run into
when unittesting. I found for me that things started to become easier
when I finally let go and let my tests drive the design. When I say
drive the design I don't mean "let the tests open up my current
design". I find that when I let the tests drive I am pushed to find
more abstractions in order to test. For instance in your ftp example
you can see it as anything that gives you a stream (not saying that
this is the best way to go in your particular case but for the sake of
illustrating). While the ftp connection will need stuff like username,
password and some URL to give you the stream, to some part of the code
it is just a stream. That part of the code can be tested with any
stream, like ByteArray[Input/Output]Stream.

Your schedule mechanism, like cron, will send an event at a given
time. To some part of the code that is just an event that was
triggered by something, if it is actually a cron-job then the event
might be the application-start. My point is, the event can be
triggered by whatever you like, including your unittests and your code
doesn't need to know (for the most part).

The actual creation of the FTP stream might require some parameters
that may be read from a configurationfile, the commandline or
whatever. So to some factory of ftp-connections they are relevant and
may be injected or read but to other parts of the system it's just a
factory (or context, or...).

I find that asking the question, "what does this code not have to know
about?" helps me.

I know that what I wrote is not rocket-science and that I'm probably
kicking in open doors but I thought in the worst case I would be the
only one learning something by kicking them in.

Hope this helps anyone.
/J

On Mon, Jul 21, 2008 at 9:18 PM, serethos_0 <Serethos@...> wrote:

> Hello!
>
> I am an quite experienced programmer but new to the philosophy of unit
> testing. An issue I want to change.
> I read some articles and took some orientation on Frank Westphal's
> very good book about that topic. But in practice, I always run into
> similar problems, which seem to disturb my view of unit testing. So
> some thought and questions I would like to discuss.
>
> 1. Recently I read that a unit test is no one if you have to touch
> network, db or filesystem. I understand the point that these accesses
> really can slow the tests down and usually need extra work of
> configuration, but how to avoid this?
> An example of my daily work. I have quite a common task: Fetch some
> xmls from an ftp server, parse the content and map it into db and vice
> versa. So the business logic is quite thin. More important is good
> exception handling and the transport of all data in the right structures.
>
> Actually the slowdown of a real ftp transport and the configuration
> and injection overhead of the db-connection is a major drawback. But
> on the other hand I see no good way to mock the behaviour of these
> endpoints.
> I could try to mock a database, but how to test, if an sql-statement
> is correct (especially for a wider range of queries)?
> It also is a very hard work to write stubs or mocks, which can answer
> with all error-states an ftp-server/network can generate (timeout,
> access denied, authentication etc) to test the correct error handling
> of my code.
>
> 2. Another question points to a basic principle of unit testing: the
> opening of a class in small and public methods. I see an advantage in
> the possibility to inject every aspect of a class (manually or e.g.
> via spring) and the code can benefit from a better readability through
> a chain of self-explanatory method calls.
> But in some cases I want to hide implementation details from the user.
> Taking my Importer/Exporter example a second time, it is more a cron
> script than an application: Doing a defined job in a robust and
> understandable manner but neither designed as a basis for wide
> enhancements nor for ultimate flexibility.
> So there are methods which start the whole work of an importer over
> the whole lifecycle (connect, fetch data, map data etc). Methods,
> which are necessary for getting the object in a usable state (e.g.
> connection established) are hidden away. To ensure that there must be
> the correct state before executing the main task I can lead the user
> with parameterized constructors (e.g. MyImporter(host, port)).
> To say it more generally I think that it is a common way to restrict
> the use of classes which need to be handled in correct order because
> of their state. This saves a lot of additional exception handling
> (e.g. executing before connecting).
> But following this thought it gets very hard to isolate testing units.
> Even when I separate the tasks within the class to units (connecting,
> disconnecting etc) they would be not accessible and would need to be
> tested from within.
>
> This is only a very simple and not a perfect example but I think my
> point should be clear. I hope that some of you take some time to read
> it. I really would appreciate some thoughts!
>
>



--
-----------------------------------------------------
Joakim Ohlrogge
Agical AB
Västerlånggatan 79, 2 tr
111 29 Stockholm, SWEDEN

Mobile: +46-708-754004
Blog: johlrogge.wordpress.com
E-mail: joakim.ohlrogge@...

RE: Newbie wants to take some JUnit group. Some basic questions.

by martinboehmsonneberg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

you are on the right way, because testing starts with asking ;-)

Nevertheless I would recommend you http://xunitpatterns.com/
The subtitle may suggest that's only about refactoring and
tuning test code but moreover it presents excellent examples
for the well known testing problems dbs, network and so on.

> -----Original Message-----
> From: junit@... [mailto:junit@...] On
> Behalf Of serethos_0
> Sent: Montag, 21. Juli 2008 21:19
> To: junit@...
> Subject: [junit] Newbie wants to take some JUnit group. Some
> basic questions.
>
> Hello!
>
> I am an quite experienced programmer but new to the
> philosophy of unit testing. An issue I want to change.
> I read some articles and took some orientation on Frank
> Westphal's very good book about that topic. But in practice,
> I always run into similar problems, which seem to disturb my
> view of unit testing. So some thought and questions I would
> like to discuss.
>
> 1. Recently I read that a unit test is no one if you have to
> touch network, db or filesystem. I understand the point that
> these accesses really can slow the tests down and usually
> need extra work of configuration, but how to avoid this?
> An example of my daily work. I have quite a common task:
> Fetch some xmls from an ftp server, parse the content and map
> it into db and vice versa. So the business logic is quite
> thin. More important is good exception handling and the
> transport of all data in the right structures.

Fetch, parse, map and persist the output are all different
tasks. Maybe its not only a testing problem just as well a
oo-design-issue. -- Because testing is thinking about design
and testabilty depends on design, I' m sure it's a problem ;-)

To do all the steps, I think its important to identify the
process, its outpu and input and the subordinate processes as
well.
So you get very finegrained units for different concerns
doing different work. And therefore you are able to mock each
other piece of unit, that cumbers you in testing your unit under
test in isolation.

> Actually the slowdown of a real ftp transport and the
> configuration and injection overhead of the db-connection is
> a major drawback. But on the other hand I see no good way to
> mock the behaviour of these endpoints.
> I could try to mock a database, but how to test, if an
> sql-statement is correct (especially for a wider range of queries)?

Let's assume you have to options:
- On a restricted range of sql-Queries validation of sql:
  So you have to test the validator and the database connection.

- On the full range of sql-Queries catch the output of the
  wrong sqls.
  So you have to test your error catcher to react and handle
  appropriatly on sql-exceptions.

Get it correct and/or react on inconsistency.
Can you see the different concerns?

> It also is a very hard work to write stubs or mocks, which
> can answer with all error-states an ftp-server/network can
> generate (timeout, access denied, authentication etc) to test
> the correct error handling of my code.

Have you tried out Mock-Frameworks like jMock or EasyMock?

> 2. Another question points to a basic principle of unit
> testing: the opening of a class in small and public methods.
> I see an advantage in the possibility to inject every aspect
> of a class (manually or e.g.
> via spring) and the code can benefit from a better
> readability through a chain of self-explanatory method calls.
> But in some cases I want to hide implementation details from the user.

First I would ask you, why you want to hide the implementation details?
When you try to hide them, then I assume thats not important for the
user and so I also assume its not a concern of the class under
test. Its the odd man out.
Then maybe its only a subtask or a task to delegate.

> Taking my Importer/Exporter example a second time, it is more
> a cron script than an application: Doing a defined job in a
> robust and understandable manner but neither designed as a
> basis for wide enhancements nor for ultimate flexibility.
> So there are methods which start the whole work of an
> importer over the whole lifecycle (connect, fetch data, map
> data etc). Methods, which are necessary for getting the
> object in a usable state (e.g.
> connection established) are hidden away. To ensure that there
> must be the correct state before executing the main task I
> can lead the user with parameterized constructors (e.g.
> MyImporter(host, port)).

"Whole" sounds like a megajob, thats not a good practice in
unit testing. Maybe the lifecycle is a separate object that
controls different tasks; the connections and fetchers are
serviceobjects that do something with your data objects.

All objects/units are easilier to test if they have one
objectiv, that you can test separatly.

> To say it more generally I think that it is a common way to
> restrict the use of classes which need to be handled in
> correct order because of their state. This saves a lot of
> additional exception handling (e.g. executing before connecting).
> But following this thought it gets very hard to isolate testing units.
> Even when I separate the tasks within the class to units
> (connecting, disconnecting etc) they would be not accessible
> and would need to be tested from within.

Why you would test from within? If the units do their thing,
they do it also within. To ensure that they do it, test it
in isolation, to be sure, that they do it really.

> This is only a very simple and not a perfect example but I
> think my point should be clear. I hope that some of you take
> some time to read it. I really would appreciate some thoughts!

Helps you to think about it?

Best Regards

>  
>

Re: Newbie wants to take some JUnit group. Some basic questions.

by Serethos :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Böhm schrieb:
> Hi,
>
> you are on the right way, because testing starts with asking ;-)
>
>  
Ohh yes, if there were not the pitfall of sitting around and asking
yourself what to do! =)

>> generate (timeout, access denied, authentication etc) to test
>> the correct error handling of my code.
>>    
> Have you tried out Mock-Frameworks like jMock or EasyMock?
>
>  
>
No, but  I hope to have soon some time investigating in EasyMock. Up to
now I am
not sure what to expect of it. With my little experience I only see the
problem of provoking
all possible error cases, e.g.:

client.login(user, pass)     // illegal arguments, authentication error,
timeout ..?

But as I said, I do not know, which help EasyMock offers me in these cases.

>> Taking my Importer/Exporter example a second time, it is more
>> a cron script than an application: Doing a defined job in a
>> robust and understandable manner but neither designed as a
>> basis for wide enhancements nor for ultimate flexibility.
>> So there are methods which start the whole work of an
>> importer over the whole lifecycle (connect, fetch data, map
>> data etc). Methods, which are necessary for getting the
>> object in a usable state (e.g.
>> connection established) are hidden away. To ensure that there
>> must be the correct state before executing the main task I
>> can lead the user with parameterized constructors (e.g.
>> MyImporter(host, port)).
>>    
>
> "Whole" sounds like a megajob, thats not a good practice in
> unit testing. Maybe the lifecycle is a separate object that
> controls different tasks; the connections and fetchers are
> serviceobjects that do something with your data objects.
>  
It sounds more than it is in my case. Such kinds of importers often are
only some glue between
data formats (xml/ db), connection handling (getting the data from a to
b) and much reboust
exception handling and logging.
Sometimes - when I really think about which class should do what in
contrast to others - I tend to
code over-ambitioned. This leads to many classes which really do their
job: connection handlers,
value or transfer objects, data mappers, controllers whatever. And there
lies a certain beauty, every
class does only what it is ment for and even better: it only knows what
i really needs. But for a simple
task like "get data from a, parse data into structure, put it into place
b" this produces lots of classes
with perhaps two methods, and some more only for building an abstraction
layer - which can be useless
if it is not part of another bigger architecture.
The endprduct can be a less beautyful code, but in best KISS manner.

> All objects/units are easilier to test if they have one
> objectiv, that you can test separatly.
>
>  
Thats the point. I see a difference between a good practice in Unit
Testing and the intention
of how the class should be used. My FTP Example (very simplified):

+FtpImporter(host, port, user, pass)
+ImporterObjects[] import()                   // calls connect()/
disconnect()
-connect()
-disconnect()
(+ some setters getters for the attributes)

It is clear that this is bad for two reasons:
- no flexibility in controlling the data-/workflow (especially open, close)
- therefore a problem in testing

But there comes the advantage I mentioned as usage intention:
- it is clear how to use the importer
- it is very hard to bring the class in an invalid state

Opening the open/close methods and offering the standard constructor for
later
code (configured) injection would offer a way to handle the class wrong:

new FtpImporter().import()   // missing connect

It would also need to put extra state validation into the connect/
disconnect methods

Said again, it is not the best example, but it shows, how hiding
implementaiton details
can lead the usage. Sure, some assumptions must be met:
- the code is _not_ made for flexibility or enhancements. I think for a
one-way-special-
case-importer this is a common simplification
- it is sure that the workflow of the program won't change in a way I
can not handle,
because the components/classes are too closed

Best greetings!



Re: Newbie wants to take some JUnit group. Some basic questions.

by J. B. Rainsberger-2 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, Jul 21, 2008 at 2:18 PM, serethos_0 <Serethos@...> wrote:

> I am an quite experienced programmer but new to the philosophy of unit
> testing. An issue I want to change.
> I read some articles and took some orientation on Frank Westphal's
> very good book about that topic. But in practice, I always run into
> similar problems, which seem to disturb my view of unit testing. So
> some thought and questions I would like to discuss.

It sounds like a very good place to start. I hope you have enjoyed
what you've read so far.

> 1. Recently I read that a unit test is no one if you have to touch
> network, db or filesystem. I understand the point that these accesses
> really can slow the tests down and usually need extra work of
> configuration, but how to avoid this?
> An example of my daily work. I have quite a common task: Fetch some
> xmls from an ftp server, parse the content and map it into db and vice
> versa. So the business logic is quite thin. More important is good
> exception handling and the transport of all data in the right structures.

I see a deeper design issue here that I want to make you aware of, but
that I don't want to tackle yet. You mention you need to fetch XML
documents from an FTP server, parse the content, then map it into a
database. Already you are describing your design in terms of
implementation details, rather than intent. Think about /why/ you need
to do these things while you read my more immediate advice.

I find good unit tests especially important to help me design
exception handling, which is why I design to interfaces. When I design
to interfaces, I can more easily control how collaborators behave, and
in particular, I can force them to throw exceptions so I can test how
I handle those exceptions. I don't know enough about your domain to
name these classes and methods meaningfully, so I'll choose
generic-sounding names that make some sense for me for now. Feel free
to suggest better names.

To test your Component, you need to tell a Database to
mapContent(content), so I create an interface Database with method
mapContent(content) and Component uses it. In this test, I want to
know that Component successfully handles an exception that Database
might throw it. Suppose if the Database throws an exception, then we
should write the XML documents back to a DocumentQueue for later
processing. You might need to do something different, but this gives
me enough to build a complete example.

@Test public void componentShouldQueueDocumentsOnDatabaseException()
throws Exception {
    Document document = new Document(....);

    CollectingDocumentQueue collectingDocumentQueue = new
CollectingDocumentQueue();

    Database crashTestDummy = new Database() {
        public void mapContent(Content content) {
            throw new RuntimeException("I blew up on purpose!");
        }
    }

    new Component(crashTestDummy,
collectingDocumentQueue).processDocument(document);

    assertEquals(Collections.singletonList(document),
collectingDocumentQueue.getDocuments());
}

I have also introduced interface DocumentQueue with method
enqueue(document) and implemented it with CollectingDocumentQueue
which simply collects all queued documents so the test can ask about
them later. The production implementation of DocumentQueue might talk
to JMS or a web service or insert the documents into a database table.
Document is a simple value or entity object that represents one of the
XML documents you fetch from your FTP server. It could even be a
simple envelope for raw XML: you can choose.

This test has a narrow focus: when you try to process a document and
the database fails, queue the document for later processing. By not
involving a real database I can easily simulate the database failing
by just implementing the Database anonymously and overriding
mapContent() to throw an exception. The production implementation of
Database could wrap any database you want: object-based, SQL, flat
files, XStream, anything.

The key part of the technique is that Component, the class under test,
takes the Database and the DocumentQueue as parameters to its
constructor. This way I can use stand-ins that make the test easier to
write, but still connect production implementations in the
application. In the test, I pass in a crash test dummy Database (a
stand-in that always throws an exception) and a spy DocumentQueue (a
stand-in that collects information about how it was used so the test
can debrief it afterwards); but in production, I pass in an SQL-based
implementation of Database and a JMS-based implementation of
DocumentQueue. Component can't tell the difference, and I believe it
shouldn't care. This modularity makes both testing and supporting new
features easier.

> Actually the slowdown of a real ftp transport and the configuration
> and injection overhead of the db-connection is a major drawback. But
> on the other hand I see no good way to mock the behaviour of these
> endpoints.

Does the above example help you see how to do it? One common technique
I use is "mock a level higher of abstraction". Don't mock SQL, but
rather mock data storage operations that SQL could implement.

> I could try to mock a database, but how to test, if an sql-statement
> is correct (especially for a wider range of queries)?

I wrote about this extensively in chapter 10 of JUnit Recipes, and
others have written extensively about it as well. Here is a short
version:

When testing whether you correctly move data from FTP server to
database, don't test whether you can fetch from FTP and don't test
whether you can INSERT into the database. Assume you can fetch() and
assume you can INSERT, then test what happens in between. When you
implement your XmlDocumentSource to be an FtpServer, then try fetching
a variety of documents without worrying about what happens after
they've been fetched, because you tested that elsewhere. When you
implement your Database to be an SqlDatabase, then try a bunch of SQL
statements without worrying about why you're executing those
particular statements, because you tested that elsewhere.

> It also is a very hard work to write stubs or mocks, which can answer
> with all error-states an ftp-server/network can generate (timeout,
> access denied, authentication etc) to test the correct error handling
> of my code.

Does the database client handle the different SQL error codes
differently? If not, then maybe one test throwing a generic
SQLException will suffice.

Does the FTP client handle the different FTP errors differently? If
not, then maybe one test throwing a generic FTP transport exception
will suffice.

Don't assume you have to test every kind of error separately if your
client always responds to errors the same way.

If, on the other hand, you do need to handle all those errors
differently, then you simply have to test for them all. If you do
less, then you're not doing your job.

> 2. Another question points to a basic principle of unit testing: the
> opening of a class in small and public methods. I see an advantage in
> the possibility to inject every aspect of a class (manually or e.g.
> via spring) and the code can benefit from a better readability through
> a chain of self-explanatory method calls.
> But in some cases I want to hide implementation details from the user.

I know two basic ways to hide implementation details: private methods
and interfaces. I prefer interfaces, since I use them to reach highly
modular designs anyhow.

> Taking my Importer/Exporter example a second time, it is more a cron
> script than an application: Doing a defined job in a robust and
> understandable manner but neither designed as a basis for wide
> enhancements nor for ultimate flexibility.

In this case, modularity makes it easier to isolate failures and
prevent defects. I find that convincing enough, even if I don't need
the additional ease-of-maintenance benefits modularity gives me.

It looks like you're thinking a lot about this. Whatever you decide to
do, thinking carefully about it is probably a great start.
--
J. B. (Joe) Rainsberger :: http://www.jbrains.ca
Your guide to software craftsmanship
JUnit Recipes: Practical Methods for Programmer Testing
2005 Gordon Pask Award for contribution Agile Software Practice

RE: Newbie wants to take some JUnit group. Some basic questions.

by martinboehmsonneberg :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Hi,

sorry, for the late answer.

> -----Original Message-----
> From: junit@... [mailto:junit@...] On
> Behalf Of Serethos
> Sent: Dienstag, 22. Juli 2008 23:43
> To: junit@...
> Subject: Re: [junit] Newbie wants to take some JUnit group.
> Some basic questions.
>
> [...]
>
> No, but I hope to have soon some time investigating in
> EasyMock. Up to now I am not sure what to expect of it. With
> my little experience I only see the problem of provoking all
> possible error cases, e.g.:
>
> client.login(user, pass) // illegal arguments, authentication
> error, timeout ..?
>
> But as I said, I do not know, which help EasyMock offers me
> in these cases.

Mock frameworks will help you in cases, when you want to manipulate
the indirect outputs and inputs of a unit. Assuming your login example
uses a connection object, this connection object will provide outputs
for the client (exceptions, login...) as well as expecting
inputs (connection parameters, network...). But these outputs and
inputs are all indirect, so the client can't directly control.

To control these inputs anyway - maybe to test how the client reacts
on connection errors - you may use an object that substitutes the
real connection object. Usally you know the main exception cases,
you are able to handle in your objects method. All other exceptions
are thrown through or you have to catch them at a deeper level.

Mock frameworks offer different substitutes for the real object.
JB already mentioned it, if you hide the real implementation
details behind interfaces, its easy to substitute, manipulate,
control etc. a dependend component.

And thats it what you realy want: Isolate your unit and control
it in a well definied environment to test all assumption as well
as unsufficiencies, for example different exceptions, you except
in your method and you can handle at this point.

> > "Whole" sounds like a megajob, thats not a good practice in unit
> > testing. Maybe the lifecycle is a separate object that controls
> > different tasks; the connections and fetchers are
> serviceobjects that
> > do something with your data objects.
> >
> It sounds more than it is in my case. Such kinds of importers
> often are only some glue between data formats (xml/ db),
> connection handling (getting the data from a to
> b) and much reboust
> exception handling and logging.
> Sometimes - when I really think about which class should do
> what in contrast to others - I tend to code over-ambitioned.
> This leads to many classes which really do their
> job: connection handlers,
> value or transfer objects, data mappers, controllers
> whatever. And there lies a certain beauty, every class does
> only what it is ment for and even better: it only knows what
> i really needs. But for a simple task like "get data from a,
> parse data into structure, put it into place b" this produces
> lots of classes with perhaps two methods, and some more only
> for building an abstraction layer - which can be useless if
> it is not part of another bigger architecture.
> The endprduct can be a less beautyful code, but in best KISS manner.

If an overall class is a sufficient solution, a simple and stupid
testcase may ensure your expectation as well. But...

> > All objects/units are easilier to test if they have one
> objectiv, that
> > you can test separatly.
> >
> >
> Thats the point. I see a difference between a good practice
> in Unit Testing and the intention of how the class should be
> used. My FTP Example (very simplified):
>
> +FtpImporter(host, port, user, pass)
> +ImporterObjects[] import() // calls connect()/
> disconnect()
> -connect()
> -disconnect()
> (+ some setters getters for the attributes)
>
> It is clear that this is bad for two reasons:
> - no flexibility in controlling the data-/workflow
> (especially open, close)
> - therefore a problem in testing
>
> But there comes the advantage I mentioned as usage intention:
> - it is clear how to use the importer
> - it is very hard to bring the class in an invalid state
>
> Opening the open/close methods and offering the standard
> constructor for later code (configured) injection would offer
> a way to handle the class wrong:

I'm not really sure if its the intended usecase for the Importer
to assume it has connected/disconnected states.

> new FtpImporter().import() // missing connect
>
> It would also need to put extra state validation into the
> connect/ disconnect methods

Thats an assumption or expectation you want to test as well.
So I see no real chance to test this aspect as well in another
way discribed by JBR.

To underline it, its easier to look onto interfaces at the
first step and don't worry about the implementation details.
From my first experience it also saves a little time, because
you don't waste your time on the uncertainity of quickly changing
implememantions - e.g. today SQL-Database-Persistence, tomorrow
some other Persistence.

>  
>