.NET Framework: 2.0
Preferred Language: C#
I am new to TDD (Test Driven Development).
First of all, is it even possible to unit test Windows Service?
Windows service class is derived from ServiceBase, which has overridable methods,
OnStart
OnStop
How can I trigger those methods to be called as if unit test is an actual service that calls those methods in proper order?
At this point, am I even doing a Unit testing? or an Integration test?
I have looked at WCF service question but it didn't make any sense to me since I have never dealt with WCF service.
I'd probably recommend designing your app so the "OnStart" and "OnStop" overrides in the Windows Service just call methods on a class library assembly. That way you can automate unit tests against the class library methods, and the design also abstracts your business logic from the implementation of a Windows Service.
In this scenario, testing the "OnStart" and "OnStop" methods themselves in a Windows Service context would then be an integration test, not something you would automate.
I have unit tested windows services by not testing the service directly, but rather testing what the service does.
Typically I create one assembly for the service and another for what the service does. Then I write unit tests against the second assembly.
The nice thing about this approach is that your service is very thin. Basically all it does is call methods to do the right work at the right time. Your other assembly contains all the meat of the work your service intends to do. This makes it very easy to test and easy to reuse or modify as needed.
I would start here. It shows how to start and stop services in C#
A sample to start is is
public static void StartService(string serviceName, int timeoutMilliseconds)
{
ServiceController service = new ServiceController(serviceName);
try
{
TimeSpan timeout = TimeSpan.FromMilliseconds(timeoutMilliseconds);
service.Start();
service.WaitForStatus(ServiceControllerStatus.Running, timeout);
}
catch
{
// ...
}
}
I have also tested services mostly through console app, simulating what the service would do. That way my unit test is completely automated.
I would use the windows service class (the one you run when you start/stop the service) sort of like a proxy to your real system. I don't see how the code behind your service should be any different from any other programming. The onStart and onStop methods are simply events being fired, like pushing a button on a GUI.
So your windows service class is a very thin class, comparable to a windows form. It calls your business logic/domain logic, which then does what it's supposed to do. All you have to do is make sure the method(s) you're calling in your onStart and onStop are working like they're supposed to. At least that's what I would do ;-)
Designing for test is a good strategy, as many of the answers point out by recommending that your OnStart and OnStop methods stay very thin by delegating to domain objects.
However, if your tests do need to execute the service methods for some reason, you can use code like this to call them from within a test method (calling OnStart in this example):
serviceInstance.GetType().InvokeMember("OnStart", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance, null, serviceInstance, new object[] {new string[] {}});
Test Window service in automatic power off, shut down conditions
Test window service when network disconnected, connected
Test window service option autostart, manual etc
Guy's probably the best answer.
Anyway, if you really want to, you could just invoke in the unit test these two method as described by MSDN documentation but, since they are protected, you'll need to use Reflection.
Related
I have a setup with some VS projects which depend on each other. Simplified, imagine these projects:
API Project (ASP.NET WebAPI 2)
DummyBackendServer (WinForms with a WCF Service)
API.Test Project (Unit Test Project which should Test API-Project's Controllers)
Usually, there would be (for example) an android client, which connects to the API-Server (1) and requests some information. The API-Server would then connect to the DummyBackendServer (2) to request these information, generate an appropriate format and send an answer to the android client.
Now I need to create some unit tests for the API-Server. My problem is, that I don't find a way to tell VS to start the DummyBackendServer (2), when it runs the unit tests. When I first start the DummyServer I can't run the tests, because the menu option is grayed out.
So, is there any way to tell VS to start another project the tests depend on?
For anyone who doesn't want to unit test the correct way and just want to run multiple projects in the same soluition, here is the answer.
Rightclick the backend project -> Debug -> Start without debugging.
The interface will not grey out so you can start other projects.
Start test with rightclick -> Run Tests
Or run your frontend with debugging as usual by having it set as startup project (Bold in the Solution Explorer) and clicking F5 or the green arrow, Start With Debugging.
Divide and conquer!
If the test (some will say that those are not unit test, but that is not part of this question) requires some services to be up - make that happen! Have them deployed to some dev or staging environment, then you only need to configure the connection from the API test assembly.
I would split the solution in two and call them integration tests. If you want them to bee unit test you have what you need from the post above.
You should use the IoC containers or something similar in your project, so you can get the mock of your other projects while run the Unit Tests.
Which one you'll select is up to you, personally I use Rhino.Mocks:
Create a mock repository:
MockRepository mocks = new MockRepository();
Add a mock object to the repository:
ISomeInterface robot = (ISomeInterface)mocks.CreateMock(typeof(ISomeInterface));
//If you're using C# 2.0, you may use the generic version and avoid upcasting:
ISomeInterface robot = mocks.CreateMock<ISomeInterface>();
"Record" the methods that you expect to be called on the mock object:
// this method has a return type, so wrap it with Expect.Call
Expect.Call(robot.SendCommand("Wake Up")).Return("Groan");
// this method has void return type, so simply call it
robot.Poke();
//Note that the parameter values provided in these calls represent those values we
//expect our mock to be called with. Similary, the return value represents the value
//that the mock will return when this method is called.
//You may expect a method to be called multiple times:
// again, methods that return values use Expect.Call
Expect.Call(robot.SendCommand("Wake Up")).Return("Groan").Repeat.Twice();
// when no return type, any extra information about the method call
// is provided immediately after via static methods on LastCall
robot.Poke();
LastCall.On(robot).Repeat.Twice();
Set the mock object to a "Replay" state where, as called, it will replay the operations just recorded.
mocks.ReplayAll();
Invoke code that uses the mock object.
theButler.GetRobotReady();
Check that all calls were made to the mock object.
mocks.VerifyAll();
I am currently writing an application which is kind of a proxy between the end-user and a web service.
The user requests a service, and the application calls the web service method with appropriate parameters set, and returns the result.
To make sure nothing went wrong, I have decided to create unit tests for the project (Yep! I know it's a bit late to do it after writing the code. I'll write the unit-tests first next time).
in these unit tests, I have to make real requests to the web service to be sure no permission exception, service-related exception, etc is raised. Therefore extracting an interface and mocking the service for testing is not going to help. Is it acceptable to write unit tests, that actually call the real web service?
Is it possible to have a delay between two tests if my web service just allows for example one request per minute?
What you are speaking about is integration test.
It's not a problem to write such tests for your web service. They are written in the same style as unit test but testing live system and or it's parts. You can even start your web service in your test context.
And it's up to you and your test context to limit situations with call delays or simulate any other situation.
My understanding is that unit tests are supposed to yield immediate result. What you are after is integration tests, not unit tests.
It is acceptable of course, although they would me more "integration tests" than unit tests, since you are testing your whole system integrated.
What you can do to delay the tests, is to simply put a Thread.sleep(1000) in the beginning of the test.
What about testing the code behind the web service layer? What I have done in the past is using web services as merely wrappers to a business logic library where all the real code lives. Then you can do integration tests on this library without worrying about your web service request limits.
I've implemented a subscribe/publish (for my own enjoyment) WCF service which works reasonably well. Like all blogs and books I've seen they all use OperationContext to get the clients callback address. After a bit of reading, due to many people saying not to use OperationContext, I found myself not being able to create proper unit tests. Yet I haven't been able to find an alternative. I suppose the subscribe method could accept a parameter for it to provide its own address? I could see the code being testable from an intergration test stand point of view but not for unit testing since OperationContext would always be null.
How do I get the clients endpoint when they subscribe to my service without using OperationContext?
Little bit of an aside but where is a good WCF resource with testing in mind when showing code samples? There are tons of blogs out there reiterating the same code without providing sample test cases.
Thank you.
Microsoft developers really like sealed and static keywords (as well as internal) and they hate virtual. Because of that standard testing approaches and framworks often don't work. You have two choices:
Wrap access to OperationContext in custom class and inject an instance of the class to your service. This will involve additional work because you will need to do injection somewhere outside your service. For example constructor injection will need custom IInstanceProvider.
Use more poweful testing framework. Check Moles framework which is able to intercept calls and redirect them. This enables "mocking" sealed classes and static methods/properties.
Another approach is simply refactoring your code. Take away all business logic from your service into separate testable business class and let the service participate only in integration test. Service is more like infrastructure and not everything really needs unit test. Integration / end-to-end / behavior test is also test and valid approach.
How can I test the following method?
It is a method on a concrete class implementation of an interface.
I have wrapped the Process class with an interface that only exposes the methods and properties I need. The ProcessWrapper class is the concrete implementation of this interface.
public void Initiate(IEnumerable<Cow> cows)
{
foreach (Cow c in cows)
{
c.Process = new ProcessWrapper(c);
c.Process.Start();
count++;
}
}
There are two ways to get around this. The first is to use dependency injection. You could inject a factory and have Initiate call the create method to get the kind of ProcessWrapper you need for your test.
The other solution is to use a mocking framework such as TypeMock, that will let you work around this. TypeMock basically allows you to mock anything, so you could use it to provide a mock object instead of the actual ProcessWrapper instances.
I'm not familiar with C# (I prefer mine without the hash), but you need some sort of interface to the process (IPC or whatever is the most convenient method) so you can send it test requests and get results back. At the simplest level, you would just send a message to the process and receive the result. Or you could have more granularity and send more specific commands from your test harness. It depends on how you have set up your unit testing environment, more precisely how you send the test commands, how you receive them and how you report the results.
I would personally have a test object inside the process that simply receives, runs & reports the unit test results and have the test code inside that object.
What does your process do? Is there any way you could check that it is doing what it's supposed to do? For example, it might write to a file or a database table. Or it might expose an API (IPC, web-service, etc.) that you could try calling with test data.
From a TDD perspective, it might make make sense to plug in a "mock/test process" that performs some action that you can easily check. (This may require code changes to allow your test code to inject something.) This way, you're only testing your invocation code, and not-necessarily testing an actual business process. You could then have different unit tests to test your business process.
How are you supposed to unit test a web service in C# with Visual Studio 2008? When I generate a unit test it adds an actual reference to the web service class instead of a web reference. It sets the attributes specified in:
http://msdn.microsoft.com/en-us/library/ms243399(VS.80).aspx#TestingWebServiceLocally
Yet, it will complete without executing the test. I attempted to add the call to WebServiceHelper.TryUrlRedirection(...) but the call does not like the target since it inherits from WebService, not WebClientProtocol.
What I usually do is not test directly against the web-service, but to try and put as little code as possible in the service, and call a different class which does all the real work. Then I write unit tests for that other class. It turns out that class can sometimes be useful outside of the web-service context, so this way - you gain twice.
If you are writing a web service, try to put all logic in another (testable) layer. Each Web method should have a little code as possible. Then you will have little reason to test the web method directly because you can test the underlying layers.
[WebMethod]
public void DoSomething()
{
hander.DoSomething();
}
If you are consuming a web method, wrap the generated caller in a class wrapper, and implement an interface for the class wrapper. Then, anytime you need to call the web service, use the interface to call the method. You want to use the interface so as to make the class wrapper swappable during testing (using Rhino Mocks, Moq, or TypeMock).
You can add a service reference to your unit test project or generate your client stub and put the class in your unit test project.
I had problems with this as well, so i use this workaround:
http://techkn0w.wordpress.com/2009/07/01/unit-testing-an-asmx-web-service-in-visual-studio-2008/
Above my web method unit tests, I have the following:
// TODO: Ensure that the UrlToTest attribute specifies a URL to an ASP.NET page (for example,
// http://.../Default.aspx). This is necessary for the unit test to be executed on the web server,
// whether you are testing a page, web service, or a WCF service.
[HostType("ASP.NET")]
[UrlToTest("http://localhost/MyWebService")]
In addition to the usual:
[TestMethod()]
[DeploymentItem("MyWebService.dll")]
This code came about from using the Visual Studio 2008 Unit Test Wizard.
Know that there are two types of Web Service. Those you write yourself and want to test, and those that you consume. For the former, the above rules apply. However, I would say that sometimes I see developers testing against external web services. Logic dictates that a third party service is unreliable and therefore requires much more testing. In object-oriented programming, it is best to understand the separation of concern that Martin Fowler and the others all told us about. This means that we should not test systems external to our own.
However, I like to write wrapper classes to provide useful functionality against the services. For example, Bing Maps has a number of amazingly powerful functions. I write tests against these just to ensure that they give me the expected values. Although not extensive, the point of them is that if the web service dies for any reason (authentication key expires, etc) then I can be informed of it via the Test Server.