2

I have the following strings:

       Actual       |   Expected
"The Actual String" | "The"
                    | "Actual"
                    | "String"
                    | "Other string"
                    |    ...

I need to create a method that will Assert that any of the Expected strings is contained in the actual string, something like this:

[TestClass]
public class UnitTest
{
    [TestMethod]
    public void TestMethod()
    {
        //Assertion Passed
        AssertContainsString("The Actual String", "The"); 

        //Assertion Passed
        AssertContainsString("The Actual String", "Something", "Actual"); 

        //Assertion Failed
        AssertContainsString("The Actual String", "Something", "Something Else"); 
    }

    public void AssertContainsString(string actual, params string[] expected)
    {

    }
}

I tried the CollectionAssert.Contains method but it didn't work. Is there a quick method I can use without iterating into the expected strings?

chaliasos
  • 9,659
  • 7
  • 50
  • 87
  • how about split actual string into words and then use `CollectionAssert.Contains`? – ie. Jun 13 '12 at 11:56

4 Answers4

2

I think it's possible to use this "StringAssert.Contains(actualString,containsubstring);" in all Framework .NET

Robert Longson
  • 118,664
  • 26
  • 252
  • 242
  • 1
    Not only does this already have an accepted answer from a year ago, but the OP also indicated that `StringAssert.Contains` did not work in his or her case. – valverij Jun 28 '13 at 14:58
1

It returns true if all the values of expected array is found in actual variable:

bool foundall = expected.Except(actual.Split(' ')).Count()==0;

Return true even if just one value is contained in the actual string:

bool ans = expected.Except(actual.Split(' ')).Count() != expected.Length;
Romil Kumar Jain
  • 20,239
  • 9
  • 63
  • 92
1

An extension method for the string class?

    public static bool AnyIn(this string s, params string[] values)
    {
        return values.Any(x => s.Contains(x));
    }

callable in this way:

    string test = "The actual string";
    if(test.AnyIn("The") == true)   // success
    ...
    if(test.AnyIn("The", "actual", "string") == true)   // success
    ...
    if(test.AnyIn("The", "actual", "value") == true)   // success
    ...
    if(test.AnyIn("some", "value") == true)   // fail

or also

    System.Diagnostics.Debug.Assert(test.AnyIn("some", "value"), "No expected string found"); // fail

of course put the extension method inside a static class
Tried also in Visual Studio 2010 Console Application

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main()
        {
            string test = "The actual string";

            // Prints False
            bool result = test.AnyIn("other", "value");
            Console.WriteLine(result.ToString()); 

            // Prints True
            result = test.AnyIn("other", "The");
            Console.WriteLine(result.ToString()); 

            //  No Assert dialog here 
            System.Diagnostics.Debug.Assert(test.AnyIn("other", "The"), "No expected values found");

            //  Big Assert dialog here with message "No expected values found"
            System.Diagnostics.Debug.Assert(test.AnyIn("other", "The"), "No expected values found");

        }

    }

    static class ext
    {
        public static bool AnyIn(this string s, params string[] values)
        {
            return values.Any(x => s.Contains(x));
        }
    }
}

EDIT:

The problem with different case could be resolved changing the extension in this way

public static bool AllIn(this string s, params string[] values)     
{         
     return values.Any(x => s.IndexOf(x + " ", StringComparison.CurrentCultureIgnoreCase) >= 0);     
}

but, to prevent false positives when one of expected strings is embedded inside the actual string you need to add a space at the end of the actual string

string test = "The actual string ";  // notice the extra space added at the end
Steve
  • 213,761
  • 22
  • 232
  • 286
  • But it fails when calling it like `test.AnyIn("other","The")` – chaliasos Jun 13 '12 at 12:27
  • @Schaliasos Uhm, no, really no, just tested with LinqPAD. – Steve Jun 13 '12 at 12:36
  • I am testing it with Visual Studio. it returns false if the 1st string in `values` is not contained in the `test` – chaliasos Jun 13 '12 at 12:45
  • @Schaliasos, At this point, just out of curiosity, I have tested also in VS2010 with a Console application and works as expected. Something is off here. Could you post your test code? – Steve Jun 13 '12 at 13:06
  • The 2nd way `System.Diagnostics.Debug.Assert` is passing but if I try to assign the result into a variable it is false – chaliasos Jun 13 '12 at 13:20
  • @Schaliasos, oh well, I don't know, just updated my answer but I don't have your results. – Steve Jun 13 '12 at 13:29
  • I am sorry, I had copy/paste your code before you changed it and I had that `return values.All(x => s.Contains(x));` instead of `Any`. Thank you very much for being patient with me. It works fine, thank you. – chaliasos Jun 13 '12 at 13:51
  • @Schaliasos no problem. It's my fault because I had not understood your question at the beginning. Just as a side note. Have you noticed that every answer given fails if the string _case_ is different ("the" doesn't match "The") – Steve Jun 13 '12 at 14:04
  • Yes I noticed that. It is failing – chaliasos Jun 13 '12 at 14:44
1

if you did

if (actual.Split(' ').Contains(expected)) return true;

but I think you would still need to iterate the expected's

foreach (string ex in expected)
{
    if (actual.Split(' ').Contains(ex)) return true;
}

EDIT as per Gene S comment

expected.Any(ex => actual.Split(' ').Contains(ex))

use the sugar if you want to, but there is no processor savings, it just makes it harder to read.

General Grey
  • 3,598
  • 2
  • 25
  • 32
  • 1
    I assumed as much, but why would you want to avoid it. Do you expect to have hundreds of objects to iterate through? if there is a cleaner way of doing it, it will simply be a syntax sugar type thing. From the computers point of view(processor), there is no way to compare things without iterating through them and comparing them – General Grey Jun 13 '12 at 12:15
  • 2
    If you want the syntactical sugar you can do this... "expected.Any(ex => actual.Split(' ').Contains(ex))"...but in the end the compiler will compile this down to a loop. – Gene S Jun 13 '12 at 12:27
  • @K'Leg Well, I really thought it might exist a faster way than the `foreach` because I want to use in Load Testing where each unit test will call the method with many expected strings. – chaliasos Jun 13 '12 at 12:36
  • @GeneS That is what I was getting it doesn't matter how yuo tell the compiler to do it, it will iterate through it the same way. – General Grey Jun 13 '12 at 12:37
  • @K'Leg Right, I was agreeing with your statement. Just decided to provide the "syntactical sugar" function you referred to, in case someone was curious. – Gene S Jun 13 '12 at 16:48