|
View:
New views
7 Messages
—
Rating Filter:
Alert me
|
|
|
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. 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.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.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.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.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. > 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.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.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. > > |
| Free Forum Powered by Nabble | Forum Help |