Search Results for

    Show / Hide Table of Contents

    Coding Standards

    In order to keep the code consistent, we follow certain conventions. Many of the choices we have made are somewhat arbitrary and could easily have gone another way. At this point, most of these conventions are already well-established, so please don't re-open a discussion about them unless you have new issues to present.

    Notice that these standards are all stylistic. Do not write standards that tell people how to program. For example, we don't need a standard that tells us to always dispose of disposable objects because that's part of the normal "standard" for C# programming. In other words, these standards are about relatively trivial things that we have all agreed to do the same way.

    Making Changes

    If you do want to make changes, please initiate a discussion of what you want to change on the developer list first. If you are intending to standardize more things than we usually standardize, it's wise to discuss it first to avoid wasting time!

    General - Please Read This

    Follow these guidelines unless you have an extremely good reason not to. Add a comment explaining why you are not following them so others will know your reasoning.

    Don't make arbitrary changes in existing code merely to conform them to these guidelines. Normally, you should only change the parts of a file that you have to edit in order to fix a bug or implement new functionality. In particular, don't use automatic formatting to change an entire file at once as this makes it difficult to identify the underlying code changes when we do a code review.

    In cases where we make broad changes in layout or naming, they should be committed separately from any bug fixes or feature changes in order to keep the review process as simple as possible. That said, we don't do this very often, since we have real work to do!

    Visual Studio can be set up to match the coding standards by importing the nunit.vssettings file from this repository. This file will only change the C# indentation and formatting settings. It will not modify any other Visual Studio settings. It can be imported into Visual Studio 2010 and later by going to Tools | Import and Export Settings...

    Copyright

    NUnit is licensed under the MIT license. Each file is prefixed by the NUnit Copyright Notice Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt enclosed in appropriate comment characters for the language of the file.

    Notes

    1. Charlie Poole and Rob Prouse are the copyright holders for the NUnit code on behalf of the NUnit community. Do not place your name on the copyright line if you wish to contribute code.

    2. The year is not included in the copyright file header.

    3. In the NUnit Framework project, you can insert the copyright header in a file using the quick fix Ctrl+. in Visual Studio.

    Language Level

    Each NUnit project sets its own C# language level. We generally aim to keep the code buildable by folks who don't necessarily have the latest compilers, so this is sometimes not the very latest level. Currently, the maximum level for most NUnit projects is C# 6.

    Note that targeting a particular level of C# does not mean that all features are available. Features are limited based on the framework targeted as well. For example, the engine currently targets .NET 2.0, which means that System.Linq extensions cannot be used in the code.

    Layout

    Namespace, Class, Structure, Interface, Enumeration and Method Definitions

    Place the opening and closing braces on a line by themselves and at the same level of indentation as their parent.

    public class MyClass : BaseClass, SomeInterface
    {
        public void SomeMethod(int num, string name)
        {
            // code of the method
        }
    }
    

    An exception may be made if a method body or class definition is empty

    public virtual void SomeMethod(int num, string name) { }
    
    public class GadgetList : List<Gadget> { }
    

    Property Definitions

    Prefer automatic backing variables wherever possible

    public string SomeProperty { get; private set; }
    

    If a getter or setter has only one statement, a single line should normally be used

    public string SomeProperty
    {
        get { return _innerList.SomeProperty; }
    }
    

    If there is more than one statement, use the same layout as for method definitions

    public string SomeProperty
    {
        get
        {
            if (_innerList == null)
                InitializeInnerList();
    
            return _innerList.SomeProperty;
        }
    }
    

    Spaces

    Method declarations and method calls should not have spaces between the method name and the parenthesis, nor within the parenthesis. Put a space after a comma between parameters.

    public void SomeMethod(int x, int y)
    {
        Console.WriteLine("{0}+{1}={2}", x, y, x + y);
    }
    

    Control flow statements should have a space between the keyword and the parenthesis, but not within the parenthesis.

    for (int i = 1; i < 10; i++)
    {
        // Do Something
    }
    

    There should be no spaces in expression parenthesis, type casts, generics or array brackets, but there should be a space before and after binary operators.

    int x = a * (b + c);
    var list = new List<int>();
    list.Add(x);
    var y = (double)list[0];
    

    Indentation

    Use four consecutive spaces per level of indent. Don't use tabs - except where the IDE can be set to convert tabs to four spaces. In Visual Studio, set the tab size to 4, the indent size to 4 and make sure Insert spaces is selected.

    Indent content of code blocks.

    In switch statements, indent both the case labels and the case blocks. Indent case blocks even if not using braces.

    switch (name)
    {
        case "John":
            break;
    }
    

    Newlines

    Methods and Properties should be separated by one blank line. Private member variables should have no blank lines.

    Blocks of related code should have not have any blank lines. Blank lines can be used to visually group sections of code, but there should never be multiple blank lines.

    If brackets are not used on a control flow statement with a single line, a blank line should follow.

    public static double GetAttribute(XmlNode result, string name, double defaultValue)
    {
        var attr = result.Attributes[name];
    
        double attributeValue;
        if (attr == null || !double.TryParse(attr.Value, NumberStyles.Any, CultureInfo.InvariantCulture, out attributeValue))
            return defaultValue;
    
        return attributeValue;
    }
    

    Naming

    The following table shows our naming standard for various types of names. All names should be clear enough that somebody unfamiliar with the code can learn about the code by reading them, rather than having to understand the code in order to figure out the names. We don't use any form of "Hungarian" notation.

    For items that may vary by project, the project’s root .editorconfig and solution DotSettings may provide the defaults and diagnostics expected for PRs in that project.

    Named Item Naming Standard Notes
    Namespaces PascalCasing
    Types PascalCasing For framework types with a special C# name, we use the C# name. So... int rather than System.Int32.
    Methods PascalCasing
    Properties PascalCasing
    Events PascalCasing
    Public and Protected Fields PascalCasing(with allowance for API compatibility) Includes constant fields.Public and protected variable fields should be avoided.
    Private and Internal Fields (may vary by project) Includes constant fields.Do not use this with fields designated by a leading underscore. Keep each file to the same standard, renaming when changes are made.Use readonly wherever appropriate for private fields.
    Parameters camelCasing
    Local Variables camelCasing

    Comments

    Use doc comments on all publicly accessible members. Keep the audience in mind. For example, comments on publicly used framework methods or attributes should be written for easy understanding by users, while comments on internal methods should target folks who work on NUnit.

    Don't comment what is obvious.

    Do comment unusual algorithms and the reasoning behind some choices made.

    Use TODO comments when needed, but make sure to go back periodically and do whatever it is!

    File Organization

    Normally, have one public type per source file. An exception is made for a simple enumeration, which is used in the interface of the public type and seems to "belong" to it. Example: TestResult and ResultState

    Name the source file after the public type it represents.

    The Directory hierarchy and Namespace hierarchy should match. For example, if the root namespace for a project is NUnit.Framework, files in the Constraints subdirectory should be in the NUnit.Framework.Constraints namespace.

    Wherever possible, classes should be laid out in the following order,

    1. Private member variables
    2. Constructors
    3. Dispose
    4. Public Properties
    5. Protected Properties
    6. Private Properties
    7. Public Methods
    8. Protected Methods
    9. Private Methods

    Using statements should be sorted as follows:

    • All System namespaces
    • All Other namespaces, including NUnit's

    It is permissible, but not required, to place using statements inside the namespace block, in shortened form, for namespaces that are descendants of the namespace itself. Note that the compiler will permit other uses of shortened namespaces within the namespace block, but we prefer to limit ourselves to descendants. Non-descendant namespaces should be listed in full form in the main using block.

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.IO;
    using NUnit.Engine.Interfaces;
    using NUnit.Engine.Internal.Execution; // OK, but inside the namespace is preferred
    
    namespace NUnit.Engine.Internal
    {
        using Execution; // Preferred location
        /* ... */
    }
    

    Use of Regions

    [Needs to be filled in]

    Use of the var keyword

    The var keyword should be used where the type is obvious to someone reading the code, for example when creating a new object. Use the full type whenever the type is not obvious, for example when initializing a variable with the return value of a method.

    var i = 12;
    var list = new List<int>();
    Foo foo = GetFoo();
    
    • Edit this page
    In this article
    Back to top Generated by DocFX | Copyright (c) 2018- The NUnit Project - Licensed under CC BY-NC-SA 4.0