Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit testing void methods?

What is the best way to unit test a method that doesn't return anything? Specifically in c#.

What I am really trying to test is a method that takes a log file and parses it for specific strings. The strings are then inserted into a database. Nothing that hasn't been done before but being VERY new to TDD I am wondering if it is possible to test this or is it something that doesn't really get tested.

like image 240
jdiaz Avatar asked Oct 29 '08 07:10

jdiaz


People also ask

Can I unit test a void method?

In conclusion, there are multiple ways to test the void method, which is dependent on the method's side-effects and what kind of test you wish to run. A unit test checks the method's functionality and can cover the void method if the side effect is stored in publicly available property.

Can we assert void methods?

Whenever we write unit test cases for any method, we expect a return value from the method. Generally, we use assert for checking if the method returns the value that we expect it to return, but in the case of void methods, they do not return any value.

How do you avoid void methods?

A method's influence should be kept as local as possible. A good way to do this is to not change the state of the class/global variables or that of the parameters passed. Doing this means, that unless you then return an output, your code is meaningless, and hence, avoid Void.

How do you unit test methods that return void C#?

First Create a void method with a ref parameter in your Class Library Solution. Out goal is to test this void method in unit test. Calling the methodRef in Test Class. Build the solution and Run TestMethod3.


10 Answers

If a method doesn't return anything, it's either one of the following

  • imperative - You're either asking the object to do something to itself.. e.g change state (without expecting any confirmation.. its assumed that it will be done)
  • informational - just notifying someone that something happened (without expecting action or response) respectively.

Imperative methods - you can verify if the task was actually performed. Verify if state change actually took place. e.g.

void DeductFromBalance( dAmount ) 

can be tested by verifying if the balance post this message is indeed less than the initial value by dAmount

Informational methods - are rare as a member of the public interface of the object... hence not normally unit-tested. However if you must, You can verify if the handling to be done on a notification takes place. e.g.

void OnAccountDebit( dAmount )  // emails account holder with info

can be tested by verifying if the email is being sent

Post more details about your actual method and people will be able to answer better.
Update: Your method is doing 2 things. I'd actually split it into two methods that can now be independently tested.

string[] ExamineLogFileForX( string sFileName );
void InsertStringsIntoDatabase( string[] );

String[] can be easily verified by providing the first method with a dummy file and expected strings. The second one is slightly tricky.. you can either use a Mock (google or search stackoverflow on mocking frameworks) to mimic the DB or hit the actual DB and verify if the strings were inserted in the right location. Check this thread for some good books... I'd recomment Pragmatic Unit Testing if you're in a crunch.
In the code it would be used like

InsertStringsIntoDatabase( ExamineLogFileForX( "c:\OMG.log" ) );
like image 198
Gishu Avatar answered Oct 03 '22 05:10

Gishu


Test its side-effects. This includes:

  • Does it throw any exceptions? (If it should, check that it does. If it shouldn't, try some corner cases which might if you're not careful - null arguments being the most obvious thing.)
  • Does it play nicely with its parameters? (If they're mutable, does it mutate them when it shouldn't and vice versa?)
  • Does it have the right effect on the state of the object/type you're calling it on?

Of course, there's a limit to how much you can test. You generally can't test with every possible input, for example. Test pragmatically - enough to give you confidence that your code is designed appropriately and implemented correctly, and enough to act as supplemental documentation for what a caller might expect.

like image 38
Jon Skeet Avatar answered Oct 03 '22 07:10

Jon Skeet


As always: test what the method is supposed to do!

Should it change global state (uuh, code smell!) somewhere?

Should it call into an interface?

Should it throw an exception when called with the wrong parameters?

Should it throw no exception when called with the right parameters?

Should it ...?

like image 24
David Schmitt Avatar answered Oct 03 '22 05:10

David Schmitt


Try this:

[TestMethod]
public void TestSomething()
{
    try
    {
        YourMethodCall();
        Assert.IsTrue(true);
    }
    catch {
        Assert.IsTrue(false);
    }
}
like image 28
Nathan Alard Avatar answered Oct 03 '22 06:10

Nathan Alard


Void return types / Subroutines are old news. I haven't made a Void return type (Unless I was being extremely lazy) in like 8 years (From the time of this answer, so just a bit before this question was asked).

Instead of a method like:

public void SendEmailToCustomer()

Make a method that follows Microsoft's int.TryParse() paradigm:

public bool TrySendEmailToCustomer()

Maybe there isn't any information your method needs to return for usage in the long-run, but returning the state of the method after it performs its job is a huge use to the caller.

Also, bool isn't the only state type. There are a number of times when a previously-made Subroutine could actually return three or more different states (Good, Normal, Bad, etc). In those cases, you'd just use

public StateEnum TrySendEmailToCustomer()

However, while the Try-Paradigm somewhat answers this question on how to test a void return, there are other considerations too. For example, during/after a "TDD" cycle, you would be "Refactoring" and notice you are doing two things with your method... thus breaking the "Single Responsibility Principle." So that should be taken care of first. Second, you might have idenetified a dependency... you're touching "Persistent" Data.

If you are doing the data access stuff in the method-in-question, you need to refactor into an n-tier'd or n-layer'd architecture. But we can assume that when you say "The strings are then inserted into a database", you actually mean you're calling a business logic layer or something. Ya, we'll assume that.

When your object is instantiated, you now understand that your object has dependencies. This is when you need to decide if you are going to do Dependency Injection on the Object, or on the Method. That means your Constructor or the method-in-question needs a new Parameter:

public <Constructor/MethodName> (IBusinessDataEtc otherLayerOrTierObject, string[] stuffToInsert)

Now that you can accept an interface of your business/data tier object, you can mock it out during Unit Tests and have no dependencies or fear of "Accidental" integration testing.

So in your live code, you pass in a REAL IBusinessDataEtc object. But in your Unit Testing, you pass in a MOCK IBusinessDataEtc object. In that Mock, you can include Non-Interface Properties like int XMethodWasCalledCount or something whose state(s) are updated when the interface methods are called.

So your Unit Test will go through your Method(s)-In-Question, perform whatever logic they have, and call one or two, or a selected set of methods in your IBusinessDataEtc object. When you do your Assertions at the end of your Unit Test you have a couple of things to test now.

  1. The State of the "Subroutine" which is now a Try-Paradigm method.
  2. The State of your Mock IBusinessDataEtc object.

For more information on Dependency Injection ideas on the Construction-level... as they pertain to Unit Testing... look into Builder design patterns. It adds one more interface and class for each current interface/class you have, but they are very tiny and provide HUGE functionality increases for better Unit-Testing.

like image 42
Suamere Avatar answered Oct 03 '22 06:10

Suamere


You can even try it this way:

[TestMethod]
public void ReadFiles()
{
    try
    {
        Read();
        return; // indicates success
    }
    catch (Exception ex)
    {
        Assert.Fail(ex.Message);
    }
}
like image 34
Reyan Chougle Avatar answered Oct 03 '22 07:10

Reyan Chougle


it will have some effect on an object.... query for the result of the effect. If it has no visible effect its not worth unit testing!

like image 28
Keith Nicholas Avatar answered Oct 03 '22 05:10

Keith Nicholas


Presumably the method does something, and doesn't simply return?

Assuming this is the case, then:

  1. If it modifies the state of it's owner object, then you should test that the state changed correctly.
  2. If it takes in some object as a parameter and modifies that object, then your should test the object is correctly modified.
  3. If it throws exceptions is certain cases, test that those exceptions are correctly thrown.
  4. If its behaviour varies based on the state of its own object, or some other object, preset the state and test the method has the correct Ithrough one of the three test methods above).

If youy let us know what the method does, I could be more specific.

like image 45
David Arno Avatar answered Oct 03 '22 05:10

David Arno


Use Rhino Mocks to set what calls, actions and exceptions might be expected. Assuming you can mock or stub out parts of your method. Hard to know without knowing some specifics here about the method, or even context.

like image 24
dove Avatar answered Oct 03 '22 06:10

dove


Depends on what it's doing. If it has parameters, pass in mocks that you could ask later on if they have been called with the right set of parameters.

like image 31
André Avatar answered Oct 03 '22 06:10

André