برچسب: should

  • Tests should be even more well-written than production code | Code4IT

    Tests should be even more well-written than production code | Code4IT


    Just a second! 🫷
    If you are here, it means that you are a software developer.
    So, you know that storage, networking, and domain management have a cost .

    If you want to support this blog, please ensure that you have disabled the adblocker for this site.
    I configured Google AdSense to show as few ADS as possible – I don’t want to bother you with lots of ads, but I still need to add some to pay for the resources for my site.

    Thank you for your understanding.
    Davide

    You surely take care of your code to make it easy to read and understand, right? RIGHT??

    Well done! 👏

    But most of the developers tend to write good production code (the one actually executed by your system), but very poor test code.

    Production code is meant to be run, while tests are also meant to document your code; therefore there must not be doubts about the meaning and the reason behind a test.
    This also means that all the names must be explicit enough to help readers understand how and why a test should pass.

    This is a valid C# test:

    [Test]
    public void TestHtmlParser()
    {
        HtmlDocument doc = new HtmlDocument();
        doc.LoadHtml("<p>Hello</p>");
        var node = doc.DocumentNode.ChildNodes[0];
        var parser = new HtmlParser();
    
        Assert.AreEqual("Hello", parser.ParseContent(node));
    }
    

    What is the meaning of this test? We should be able to understand it just by reading the method name.

    Also, notice that here we are creating the HtmlNode object; imagine if this node creation is present in every test method: you will see the same lines of code over and over again.

    Thus, we can refactor this test in this way:

     [Test]
    public void HtmlParser_ExtractsContent_WhenHtmlIsParagraph()
    {
        //Arrange
        string paragraphContent = "Hello";
        string htmlParagraph = $"<p>{paragraphContent}</p>";
        HtmlNode htmlNode = CreateHtmlNode(htmlParagraph);
        var htmlParser = new HtmlParser();
    
        //Act
        var parsedContent = htmlParser.ParseContent(htmlNode);
    
        //Assert
        Assert.AreEqual(paragraphContent, parsedContent);
    }
    

    This test is definitely better:

    • you can understand its meaning by reading the test name
    • the code is concise, and some creation parts are refactored out
    • we’ve well separated the 3 parts of the tests: Arrange, Act, Assert (we’ve already talked about it here)

    Wrapping up

    Tests are still part of your project, even though they are not used directly by your customers.

    Never skip tests, and never write them in a rush. After all, when you encounter a bug, the first thing you should do is write a test to reproduce the bug, and then validate the fix using that same test.

    So, keep writing good code, for tests too!

    Happy coding!

    🐧



    Source link

  • 5 tricks every C# dev should know about LINQPad &vert; Code4IT

    5 tricks every C# dev should know about LINQPad | Code4IT


    LINQPad is one of the tools I use daily. But still, I haven’t used it at its full power. And you?

    Table of Contents

    Just a second! 🫷
    If you are here, it means that you are a software developer.
    So, you know that storage, networking, and domain management have a cost .

    If you want to support this blog, please ensure that you have disabled the adblocker for this site.
    I configured Google AdSense to show as few ADS as possible – I don’t want to bother you with lots of ads, but I still need to add some to pay for the resources for my site.

    Thank you for your understanding.
    Davide

    LINQPad is one of my best friends: I use it daily, and it helps me A LOT when I need to run some throwaway code.

    There are many other tools out there, but I think that LINQPad (well, the full version!) is one of the best tools on the market.

    But still, many C# developers only use just a few of its functionalities! In this article, I will show you my top 5 functionalities you should know.

    Advanced Dump()

    As many of you already know, to print stuff on the console you don’t have to call Console.WriteLine(something), but you can use something.Dump();

    void Main()
    {
        var user = new User(1, "Davide", "DavideB");
        user.Dump();
    }
    

    Basic usage of Dump()

    You can simplify it by avoiding calling the Dump operation in a separate step: Dump can print the content and return it at the same time:

    var user = new User(1, "Davide", "DavideB").Dump();
    

    Dump() can both print and return a value

    For sure, this simple trick makes your code easier to read!

    Ok, what if you have too many Dump calls and you don’t know which operation prints which log? Lucky for us, the Dump method accepts a string as a Title: that text will be displayed in the output panel.

    var user = new User(1, "Davide", "DavideB").Dump("My User content");
    

    You can now see the “My User content” header right above the log of the user:

    Dump() with title

    Dump containers

    We can do a step further and introduce Dump containers.

    Dump Containers are some sort of sink for your logs (we’ve already talked about sinks, do you remember?). Once you’ve instantiated a DumpContainer object, you can perform some operations such as AppendContent to append some content at the end of the logs, ClearContent to clear the content (obviously!), and Dump to display the content of the Container in the Results panel.

    DumpContainer dc = new DumpContainer();
    
    dc.Content = "Hey!";
    dc.AppendContent("There");
    
    dc.Dump();
    

    Note: you don’t need to place the Dump() instruction at the end of the script: you can put it at the beginning and you’ll see the content as soon as it gets added. Otherwise, you will build the internal list of content and display it only at the end.

    So, this is perfectly valid:

    DumpContainer dc = new DumpContainer();
    dc.Dump();
    
    
    dc.Content = "Hey!";
    dc.AppendContent("There");
    

    Simple usage of Dump container

    You can even explicitly set the content of the Container: setting it will replace everything else.

    Here you can see what happens when we override the content:

    Replace log content with DumpContainer

    Why should we even care? 🤔

    My dear friend, it’s easy! Because we can create more Containers to log different things!

    Take this example: we want to loop over a list of items and use one Container to display the item itself, and another Container to list what happens when we perform some operations on each item. Yeeees, I know, it’s hard to understand in this way: let me show you an example!

    DumpContainer dc1 = new DumpContainer();
    DumpContainer dc2 = new DumpContainer();
    
    dc1.Dump();
    dc2.Dump();
    
    var users = new List<User> {
        new User(1, "Davide", "DavideB"),
        new User(2, "Dav", "Davi Alt"),
        new User(3, "Bellone", "Bellone 3"),
    };
    
    foreach (var element in users)
    {
        dc1.AppendContent(element);
        dc2.AppendContent(element.name.ToUpper());
    }
    

    Here we’re using two different containers, each of them lives its own life.

    Using multiple containers

    In this example I used AppendContent, but of course, you can replace the full content of a Container to analyze one item at a time.

    I can hear you: there’s another question in your mind:

    How can we differentiate those containers?

    You can use the Style property of the DumpContainer class to style the output, using CSS-like properties:

    DumpContainer dc2 = new DumpContainer();
    dc2.Style = "color:red; font-weight: bold";
    

    Now all the content stored in the dc2 container will be printed in red:

    Syling DumpContainer with CSS rules

    Great stuff 🤩

    Read text from input

    Incredibly useful, but often overlooked, is the ability to provide inputs to our scripts.

    To do that, you can rely on the Util.ReadLine method already included in LINQPad:

    string myContent = Util.ReadLine();
    

    When running the application, you will see a black box at the bottom of the window that allows you to write (or paste) some text. That text will then be assigned to the myContent variable.

    Using input in LINQPad

    There’s a nice overload that allows you to specify a sort of title to the text box, to let you know which is the current step:

    Input boxes can have a title

    Paste as escaped string

    This is one of my favorite functionalities: many times I have to escape text that contains quotes, copied from somewhere else to assign it to a string variable; I used to lose time escaping those values manually (well, using other tools that still are slower than this one).

    Take this JSON:

    {
      "name": "davide",
      "gender": "male",
      "probability": 0.99,
      "count": 82957
    }
    

    Assigning it manually to a string becomes a mess. Lucky for us, we can copy it, get back on LINQPad, right-click, choose “Paste as escaped string” (or, if you prefer, use Alt+Shift+V) and have it already escaped and ready to be used:

    Escaped string in LINQPad

    That operation will generate this string:

    string content = "{\n\t\"name\": \"davide\",\n\t\"gender\": \"male\",\n\t\"probability\": 0.99,\n\t\"count\": 82957\n}";
    

    Not bad, isn’t it? 😎

    xUnit test support

    Another nice functionality that you can use to toy with classes or methods you don’t know is the xUnit test support.

    By clicking on the Query > Add XUnit Test Support, you can add xUnit to your query and write (and run, obviously) unit tests.

    All those tests are placed in a region named Tests:

    and can be run both by pressing Alt+Shift+T or by calling RunTests() in the Main method.

    After running the tests you will see a report with the list of the tests that passed and the details of the tests that failed:

    xUnit test result

    This article first appeared on Code4IT

    Wrapping up

    We’ve seen 5 amazing tricks to get the best out of LINQPad. In my opinion, every C# developer that uses this tool should know those tricks, they can really boost your productivity.

    Did you already know all of them? Which are your favorites? Drop a message in the comments section or on Twitter 📧

    Happy coding!

    🐧





    Source link

  • Methods should have a coherent level of abstraction &vert; Code4IT

    Methods should have a coherent level of abstraction | Code4IT


    Just a second! 🫷
    If you are here, it means that you are a software developer.
    So, you know that storage, networking, and domain management have a cost .

    If you want to support this blog, please ensure that you have disabled the adblocker for this site.
    I configured Google AdSense to show as few ADS as possible – I don’t want to bother you with lots of ads, but I still need to add some to pay for the resources for my site.

    Thank you for your understanding.
    Davide

    Mixed levels of abstraction make the code harder to understand.

    At the first sight, the reader should be able to understand what the code does without worrying about the details of the operations.

    Take this code snippet as an example:

    public void PrintPriceWithDiscountForProduct(string productId)
    {
        var product = sqlRepository.FindProduct(productId);
        var withDiscount = product.Price * 0.9;
        Console.WriteLine("The final price is " + withDiscount);
    }
    

    We are mixing multiple levels of operations. In the same method, we are

    • integrating with an external service
    • performing algebraic operations
    • concatenating strings
    • printing using .NET Console class

    Some operations have a high level of abstraction (call an external service, I don’t care how) while others are very low-level (calculate the price discount using the formula ProductPrice*0.9).

    Here the readers lose focus on the overall meaning of the method because they’re distracted by the actual implementation.

    When I’m talking about abstraction, I mean how high-level an operation is: the more we stay away from bit-to-bit and mathematical operations, the more our code is abstract.

    Cleaner code should let the reader understand what’s going on without the need of understanding the details: if they’re interested in the details, they can just read the internals of the methods.

    We can improve the previous method by splitting it into smaller methods:

    public void PrintPriceWithDiscountForProduct(string productId)
    {
        var product = GetProduct(productId);
        var withDiscount = CalculateDiscountedPrice(product);
        PrintPrice(withDiscount);
    }
    
    private Product GetProduct(string productId)
    {
        return sqlRepository.FindProduct(productId);
    }
    
    private double CalculateDiscountedPrice(Product product)
    {
        return product.Price * 0.9;
    }
    
    private void PrintPrice(double price)
    {
        Console.WriteLine("The final price is " + price);
    }
    

    Here you can see the different levels of abstraction: the operations within PrintPriceWithDiscountForProduct have a coherent level of abstraction: they just tell you what the steps performed in this method are; all the methods describe an operation at a high level, without expressing the internal operations.

    Yes, now the code is much longer. But we have gained some interesting advantages:

    • readers can focus on the “what” before getting to the “how”;
    • we have more reusable code (we can reuse GetProduct, CalculateDiscountedPrice, and PrintPrice in other methods);
    • if an exception is thrown, we can easily understand where it happened, because we have more information on the stack trace.

    You can read more about the latest point here:

    🔗 Clean code tip: small functions bring smarter exceptions | Code4IT

    This article first appeared on Code4IT 🐧

    Happy coding!

    🐧



    Source link