none
Pass Memory stream & string builder as parameters to C# class RRS feed

  • Question

  • Rephrasing my question :

    current class :

        public someclass(stream Stream, stringbuilder builder)  
        {
           stream = new stream; 
           builder = new StringBuilder (); 
        }

    So it is not mockable and unit testable. What i wish to achieve is that pass both stream & stringbuilder as dependencies to this class so that the constructor looks something like this : 

        public someclass(IStreamProvider streamprovider, IStringbuilderProvider builderProvider)  
        {
           stream = streamProvider.GetStream(); 
           builder = builderprovider.GetBuilder(); 
        }

    Later on I can mock IStreamProvider and IStringbuilderProvider and setup Get methods on the same.

    Is this approach correct ? Any suggestions ?


    • Edited by Gausha Sunday, December 30, 2018 7:35 PM
    Saturday, December 29, 2018 5:31 AM

All replies

  • You may try this method:

    <style type="text/css">@page { margin: 2cm } pre.cjk { font-family: "DejaVu Sans Mono", monospace } p { margin-bottom: 0.25cm; line-height: 120% } a:link { so-language: zxx } </style>
    using System;
    using System.Text;
    
    class Program
    {
     static void Main()
     {
     string[] items = { "Cat", "Dog", "Celebrity" };
    
     StringBuilderbuilder2 = new StringBuilder(
     "These items are required:").AppendLine();
    
     foreach(string item in items)
     {
     builder2.Append(item).AppendLine();
     }
     Console.WriteLine(builder2.ToString());
     Console.ReadLine();
     }
    }
    
    Output
    
    These items are required:
    Cat
    Dog
    Celebrity


    Saturday, December 29, 2018 7:23 AM
  • If you want to have class unit testable you need dependency inversion (not injection). It means lower layer is depend on higher layer (not vice versa). Loose coupling makes sense when you use it between domain layer and other layer. You want to do loose coupling between your class and .NET Framework class. It doesn't make sense because .NET Framework is technology, it is not layer of your application.
    Saturday, December 29, 2018 10:38 AM
  • Hi uk3435,

    Thank you for posting here.

    According to your issue, I want to confirm a question with you.

    Do you want to pass the stream and builder in the first constructor to the second constructor?

    If so, I will tell you it is impossible for you to do that, because the parameters in the first constructor are just local variables, they cannot be accessed outside the parentheses.

    We are waiting for your update.

    Best regards,

    Jack


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, December 31, 2018 9:57 AM
    Moderator
  • Mocking either of these doesn't make sense to me. Why are you trying to mock them? They are testable already. You can pass a MemoryStream (or any mockable-stream you want) to the constructor for the first parameter. Personally I'd use MemoryStream initialized with the data I expected. If you need to "test" intermittent failures then mocking the Stream class is doable since it is abstract.

    StringBuilder is a framework type so I cannot imagine any scenario where you would need to mock it. You can easily verify it contains the expected results on the other side of your test. Can you clarify why you would want/need to mock either of these types?

    Adding "extra" interfaces to make a type "testable" is wrong. Interfaces are for design purposes, not testing. So I would be strongly against adding interfaces "just to test". StringBuilder in particular doesn't make sense because it is sealed. You cannot create new types from it anyway. The only purpose a "provider" interface would have is to be able to create the instance on demand but that is what DI is for already. In your unit tests you probably aren't using DI but your individual tests can pass in any "builder" you want.

    Finally, in answer to your original question I wouldn't use an interface but a factory. All popular DI containers support them without any extra configuration.

    public someclass ( Func<stream> stream, Func<StringBuilder> builder )
    {
    }
    Again, in this, you are gaining nothing by doing this other than making it harder to use. But that is how you could implement the "provider" interface without the need for yet another type.


    Michael Taylor http://www.michaeltaylorp3.net

    Monday, December 31, 2018 2:49 PM
    Moderator
  • I remember I needed to do it when we have MessageBus in projet. For testing purposes I needed to create mock of message bus to get message. I created it by MessageBus encapsulation. It means I defined interface with functionality which I needed. Then I implement this interface by encapsulation of MessageBus object for normal working. For unit test I implement interface by fake class. I needed to do it because I didn't have access to message bus and I needed to simulate to got message from bus. But I cannot imagine to use it for Stream or StringBuilder. Stream could be part of infrastructure and there could be problem on share storages accessing though username and password. But what about StringBuilder? I cannot imagine it is part of infrastructure to need create mock of it.
    Monday, December 31, 2018 4:42 PM