One reason for why unit testing has bothered me is that it goes against an OO principle I was thought at school, namely that every aspect of the code should be kept as private as possible.
Roy Osherove has a recent entry on this subject. Roy is an enthusiastic unit-tester, I am still in doubt :)
UPDATED 24.7.2007
Bruce Eckel's thoughts on OOP.
Monday, February 26, 2007
Tuesday, February 20, 2007
TDD presupposition
I am pondering the validity of the following statement:
I know that this is taken as a given in unit-test camps, but is it?
UPDATED: 1.1.2008
I found out that I am not alone in not being convinced about designing for testability. The creator of TypeMock feels that designing for testability does not comply with YAGNI.
"The theory is that testable code is better designed ... If the class is easier to test, it is a better design. The test first paradigm just forces you to use good design. It makes a good design the path of least resistance." -David Hogue
I know that this is taken as a given in unit-test camps, but is it?
UPDATED: 1.1.2008
I found out that I am not alone in not being convinced about designing for testability. The creator of TypeMock feels that designing for testability does not comply with YAGNI.
Monday, February 19, 2007
Seeing the log4net output when testing under TestDriven.NET
[Update 22.02.] It is also possible to use the log4net configuration for the service or executable that will be calling the dll under test. To to this three things have to be done:
I found a nice way to be able to see the log4net output when unit testing under TestDriven.NET:
- Link the App.config file of the service or executable to the UnitTests project
- Include a
ILog sLogger = LogManager.GetLogger(typeof(IsmClientWatchdog));
in the test class, even thought sLogger is never used therein. - Add
[assembly: log4net.Config.XmlConfigurator(Watch=true)]
to the UnitTests project's AssemblyInfo.cs
XmlConfigurator.Configure()[Original post]
I found a nice way to be able to see the log4net output when unit testing under TestDriven.NET:
log4net.Appender.ConsoleAppender app;
[TestFixtureSetUp]
public void Init()
{
app = new log4net.Appender.ConsoleAppender();
app.Layout = new log4net.Layout.PatternLayout("%d %C{1} [%-5p] : %m%n");
app.Threshold = log4net.Core.Level.All;
log4net.Config.BasicConfigurator.Configure(app);
}
[TestFixtureTearDown]
public void Dispose()
{
app.Threshold = log4net.Core.Level.Off;
}
Saturday, February 17, 2007
Unit testing, lessons learned
I was doing a small application and thought of using the opportunity to see what additional effort it would require to make it unit-testable.
- Two projects had to be added to the solution: A class library project where the code to be tested has been factored out, and a class library containing the unit-tests.
- The configuration could no longer be read directly from the app.config, because it had to be changable programatically, so a ConfigurationManager had to be introduced.
- An additional interface had to be introduced for the ConfigurationManager so that it could be stubbed out.
- A second constructor had to be added which took a ConfigurationManager as a parameter.
- The run method contained an infinite while loop and needed therefore to be split into two methods.
- Finally, all the unit-tests, of course, had to be written :)
Thursday, February 15, 2007
Visual Studio 2003 templates
The standard template for a new class in VS 2003 has been slightly irritating to me :) I finally googled this issue and found two nice articles by Michael Groeger on the subject. The first one is about changing the "Add Class..." template. The second one describes how to create a new template for Nunit test classes.
To the default class template I added copyright information and $Date$, $Author$, and $Rev$ keywords for Subversion. As well as removing the irritating: " TODO: Add constructor logic here" :)
To the default class template I added copyright information and $Date$, $Author$, and $Rev$ keywords for Subversion. As well as removing the irritating: " TODO: Add constructor logic here" :)
More on unit tests
Software development gurus, in a mistaken attempt to simplify things, make up simple rules for us simple people to follow. I think a better approach is giving us the arguments to decide by ourselves on a case-by-case bases how, or if, to use the tool or method in question.Should unit tests be used always and unconditionally?
I have been giving unit tests some thought. Unit tests are a tool and I am not religious about when to apply it. Sometimes I might mock out some external dependencies, but at other times I would like to test that dependency as well. It is often a compromise between complicating the code, and mock out external dependencies. E.g. should I introduce a configuration manager so that I can make the code independent of the database, or should I just include retrieving the configuration from the database in the test? I don't believe in using unit tests all the time, sometimes it is just too difficult to set-up the test. They should be used when the tests need to be repeatable for regression purposes. Sometimes you just know that you are not going to change that piece of code and then it is sufficient, simpler, and faster to test it manually until it works as intended :)
Another issue I have with unit tests is that they can lull one into thinking it is ok to make a change and accept it as good if no red lights appear in the test runner. The correct procedure, however, is to check if there is actually a unit test that covers the code you just changed, because, initially , it might have been deemed not feasible to create unit tests for that particular scenario.
I might be stating the obvious (it is often needed), but unit tests are a tool that should not be applied automatically or relied on blindly :)
I have been giving unit tests some thought. Unit tests are a tool and I am not religious about when to apply it. Sometimes I might mock out some external dependencies, but at other times I would like to test that dependency as well. It is often a compromise between complicating the code, and mock out external dependencies. E.g. should I introduce a configuration manager so that I can make the code independent of the database, or should I just include retrieving the configuration from the database in the test? I don't believe in using unit tests all the time, sometimes it is just too difficult to set-up the test. They should be used when the tests need to be repeatable for regression purposes. Sometimes you just know that you are not going to change that piece of code and then it is sufficient, simpler, and faster to test it manually until it works as intended :)
Another issue I have with unit tests is that they can lull one into thinking it is ok to make a change and accept it as good if no red lights appear in the test runner. The correct procedure, however, is to check if there is actually a unit test that covers the code you just changed, because, initially , it might have been deemed not feasible to create unit tests for that particular scenario.
I might be stating the obvious (it is often needed), but unit tests are a tool that should not be applied automatically or relied on blindly :)
Monday, December 18, 2006
Limitation of foreign-key constraints in SQL Server 2005
I encountered a limitation to how you can set the on-delete and on-update constraints for foreign-keys in SQL Server 2005. I have a table with 5 foreign-keys, all targeting the same column. I wished to have on-delete and on-update "Cascade" for all of them, this however was not permitted. Only one of them could have the cascade property set, the others I left with "No action"
.
Units tests as an afterthought
This has probably been said elsewhere and I might even have read it there ;) Still I think it is worth mentioning here.
Ideally unit tests should written as a part of a test driven design (TDD), in this case they check for code's correctness. However, sometimes the unit tests don't get done
instead the code is made bug-free by testing it by hand. In this case it is still of value to write unit tests, however the focus changes: The unit tests should guard the code against external changes that affect it, i.e. ensuring its pre-conditions. These unit tests test things such as:
Ideally unit tests should written as a part of a test driven design (TDD), in this case they check for code's correctness. However, sometimes the unit tests don't get done
instead the code is made bug-free by testing it by hand. In this case it is still of value to write unit tests, however the focus changes: The unit tests should guard the code against external changes that affect it, i.e. ensuring its pre-conditions. These unit tests test things such as:- DB schema changes: E.g. the code should still be able to load its configuration from the database.
- Interfaces to external code: Just the simplest run through the code where all external interfaces are called should trigger test failure. This is not such an issue for strongly types languages, except where reflection is used.
Linking files between projects in VS2003
Thursday, December 14, 2006
Secrets distract
Another interesting post at Chris Sells spoutlet was about the flow of information within companies. I think he is quite right in saying that secrets should not be withheld from employees.
Data will outlive programs
I got a small epiphany when reading an old entry by Chris Sells. It made me realize that the data in the database should be left as accessible as possible for future programs. The data will most likely outlive the program created to access it.
P.s.
Actually, the reason I ended up at Chris was because he had made available a nice tool to test regular expressions.
P.s.
Actually, the reason I ended up at Chris was because he had made available a nice tool to test regular expressions.
Thursday, March 02, 2006
SqlServer: indexes
Some points to remember about indexes in SqlServer 2000:
- Primary key is a clustered unique index, but can be changed to non-clustered.
- Clustered index: Data is physically sorted by the index. Important to keep the most selective column first in the index definition. Only one clustered index possible per table. If there is only one index on a table it should be clustered. Preferably the indexed column should contain a monotonically increasing value.
- Non-clustered index: Symbolic links. Useful for single row look-ups. Can be up to 250 non-clustered indexes on a given table.
- Select indexes based on perceived use of the table: what selects will be performed, what updates will be performed, etc.
Wednesday, March 01, 2006
Missing information on Remoting
I am missing a more detailed documentation on Remoting. Not for the lack of trying: I read the Msdn documentation and we own Ingo Rammer's "Advanced .NET Remoting". Specifically I would like to know the socket options used by the TCP channel and if the size of the Remoting ThreadPool can be easily changed, per application.
Are WeakReferences used in Remoting?
Are WeakReferences used in Remoting?
Thursday, February 23, 2006
System.Console in .NET 2.0
I like to use the Console to do small test applications and it bothered me how limited it is. E.g., I have not been able to control where to place the text in the console window. In .NET 2.0 the Console class has now been much updated, e.g., there is the great new function SetCursorPosition() :)
Another missing functionality in the Console 1.0 class is a non-blocking Peak(). This is useful as a condition in a while-loop (instead of spawning a second thread that blocks on Peak() or Read()). In version 2.0 there is now the KeyAvailable property that (supposedly) serves this purpose.
This is just to mention two of the many additions to the Control class.
Another missing functionality in the Console 1.0 class is a non-blocking Peak(). This is useful as a condition in a while-loop (instead of spawning a second thread that blocks on Peak() or Read()). In version 2.0 there is now the KeyAvailable property that (supposedly) serves this purpose.
This is just to mention two of the many additions to the Control class.
Tuesday, February 21, 2006
Categorization of tests
I thought the following categorization of tests sufficient and complete:
"I believe that the traditional testing terms; unit tests, integration tests and system tests have become outdated. Instead I prefer the terms developer tests, functional tests and non-functional tests. Non-functional tests are things like performance testing, functional tests are tests that the customer cares about like use case tests or business transaction tests, and developer tests are everything else that the developer needs to test to prove to herself that the code is correct."
- Agile Development Checklist
"I believe that the traditional testing terms; unit tests, integration tests and system tests have become outdated. Instead I prefer the terms developer tests, functional tests and non-functional tests. Non-functional tests are things like performance testing, functional tests are tests that the customer cares about like use case tests or business transaction tests, and developer tests are everything else that the developer needs to test to prove to herself that the code is correct."
- Agile Development Checklist
Monday, February 06, 2006
C# 3.0
I read (skimmed through) Don Box's and Anders Hejlsberg's article on LINQ, also watched a short demonstration on DLINQ to become acquainted with next version of C#. One thing struck me and that is that Microsoft has been advocating the use of stored procedures rather than inline queries, but the DLINQ presentation was all about how to write compile-time-checked inline queries.
Hmmm...
Hmmm...
Friday, January 20, 2006
Article on agile development
I read an article on agile development by Martin Fowler. I thought it was an excellent read. Just to get you excited I have extracted some of the points I found most interesting.
Traditional engineering and software development differ in a significant way. E.g., in building a bridge the design is about 10% of the effort, but in software development it is about 50% of the effort. This changes the nature of the work since design is a much more unpredictable process, requiring gifted (non replaceable) individuals, but construction is rather automated and less demanding on particular skills. Additionally, the requirements for software projects are more liquid making the software design process even harder to predict.
Since the individual developer plays such a big role in a software development the agile processes are focuses on how to mange them and their interactions, as opposed to the traditional approach based on the assumption that the individuals are replaceable parts. Finding a good measure of progress for these processes is difficult, and Martin quotes Robert Austin's conclusion that measurement-based management has to be abandoned for delegatory management.
The unpredictability of software development makes it hard to fix a budged up-front: it is impossible to fix time, price and scope. However, using agile methods, it is possible to allow the scope to vary while keeping the price and time fixed. The success of the project should therefore be measured by how much business-value it provides to the customer, rather than how well it meets its plan.
Martin concludes his article by describing some of the numerous agile methods in existence, this I found of less interest.
Traditional engineering and software development differ in a significant way. E.g., in building a bridge the design is about 10% of the effort, but in software development it is about 50% of the effort. This changes the nature of the work since design is a much more unpredictable process, requiring gifted (non replaceable) individuals, but construction is rather automated and less demanding on particular skills. Additionally, the requirements for software projects are more liquid making the software design process even harder to predict.
Since the individual developer plays such a big role in a software development the agile processes are focuses on how to mange them and their interactions, as opposed to the traditional approach based on the assumption that the individuals are replaceable parts. Finding a good measure of progress for these processes is difficult, and Martin quotes Robert Austin's conclusion that measurement-based management has to be abandoned for delegatory management.
The unpredictability of software development makes it hard to fix a budged up-front: it is impossible to fix time, price and scope. However, using agile methods, it is possible to allow the scope to vary while keeping the price and time fixed. The success of the project should therefore be measured by how much business-value it provides to the customer, rather than how well it meets its plan.
Martin concludes his article by describing some of the numerous agile methods in existence, this I found of less interest.
Thursday, January 19, 2006
Using database transactions in unit tests
I started using the advice of Roy Osherove regarding how to use transactions in unit tests (see previous blog entry).
To summarize the method:
This code worked fine after having sorted out some configuration problems. I am accessing the SQL Server 2000 on a Windows 2003 server from a Windows XP on a different domain. First I got "The partner transaction manager has disabled its support for remote/network transactions.", this changed when I allowed for MSDTC on the server. Then I got "The transaction manager has disabled its support for remote/network transactions" which was fixed by allowing MSDTC on the client machine. The final error was because the firewall was blocking the connection.
Therefore in order to make this work (for this scenario) it is necessary to:
Now I am able to control the initial conditions of the database programmatically in a simple manner :)
P.s. The above settings work for me, but further instructions can be had here and here.
To summarize the method:
using System.EnterpriseServices;
ServiceConfig config = new ServiceConfig();
config.Transaction= TransactionOption.RequiresNew;
ServiceDomain.Enter(config);
[database CRUD code]
if(ContextUtil.IsInTransaction)
{
ContextUtil.SetAbort();
}
ServiceDomain.Leave();
This code worked fine after having sorted out some configuration problems. I am accessing the SQL Server 2000 on a Windows 2003 server from a Windows XP on a different domain. First I got "The partner transaction manager has disabled its support for remote/network transactions.", this changed when I allowed for MSDTC on the server. Then I got "The transaction manager has disabled its support for remote/network transactions" which was fixed by allowing MSDTC on the client machine. The final error was because the firewall was blocking the connection.
Therefore in order to make this work (for this scenario) it is necessary to:
- Allow MSDCT on the client and server: Administration tools -> Component Services -> Computers, right-click on My Computer, click on the "MSDTC" tab, click on "Security Configuration" and allow everything :) In particular: "Allow Outbound" on client, "Allow Inbound" on server (the SQL Server machine), set "No Authentication Required" on both server and client, and enable TIP and XA Transactions on both server and client.
- In the firewall open up for the msdtc.exe: %root%\WINDOWS\system32\msdtc.exe on both client and server.
Now I am able to control the initial conditions of the database programmatically in a simple manner :)
P.s. The above settings work for me, but further instructions can be had here and here.
Wednesday, January 18, 2006
Interesting figures
On Tomshardware there is a interesting short comparison on present and past computer capabilities.
Wednesday, December 21, 2005
Unit testing reality
I has been a pleasure reading Roy Osherove's articles on unit testing. In "Write Maintainable Unit Tests That will Save You Time And Tears" he talks about some of the pitfalls of unit testing, the list is probably not complete, but I good read.
On a side-note: I feel that articles written with the intention of explaining shortcomings (scope) and pitfalls are much more educational then the ones simply explaining the usage. I felt this strongly when reading about Fitness where I had problems in figuring out its scope.
The other article, discussed unit testing database access layer code. It had the excellent suggestion of using COM+ 1.5 SWC to encapsulate the unit tests in transactions, thus ensuring independence between unit test. I am looking forward to following this suggestion.
On a side-note: I feel that articles written with the intention of explaining shortcomings (scope) and pitfalls are much more educational then the ones simply explaining the usage. I felt this strongly when reading about Fitness where I had problems in figuring out its scope.
The other article, discussed unit testing database access layer code. It had the excellent suggestion of using COM+ 1.5 SWC to encapsulate the unit tests in transactions, thus ensuring independence between unit test. I am looking forward to following this suggestion.
Subscribe to:
Posts (Atom)
