100

I can't seem to find an assertion in PHPUnit that simply tests if a string is contained somewhere in another string. Trying to do something like this:

public function testRecipe() {

    $plaintext = get_bread_recipe();

    $this->assertStringContains('flour', $plaintext);

}

What real assertion would I put instead of assertStringContains ? I would prefer not having to worry about regex in this case because there is absolutely no need for it.

It's so simple that there must be something I have overlooked, but I just can't figure it out! Funny enough there is assertStringStartsWith() and assertStringEndsWith()!

Update: I know strpos() !== false could be used but I'm looking for something cleaner. If I just use vanilla PHP functions anyway what's the whole point with all the assertions then...

TheStoryCoder
  • 3,403
  • 6
  • 34
  • 64
  • 1
    There's no such method to do that, however you can use `$this->assertGreaterThan(0, strpos($plaintext, 'flour'));` – Bartek Jun 03 '14 at 13:14
  • 1
    @bartek That will fail if the string starts with 'flour' – GordonM Jun 03 '14 at 13:20
  • @GordonM Right, in this case `-1` will do the trick – Bartek Jun 03 '14 at 13:22
  • 1
    @bartek That still won't work. You have to do a strict test for FALSE – GordonM Jun 03 '14 at 13:23
  • 6
    See, this is exactly why I wanted that specific assertion - the confusion is already evident here! – TheStoryCoder Jun 03 '14 at 13:48
  • @TheStoryCoder Welcome to PHP development :) – GordonM Jun 03 '14 at 14:26
  • You can always extend the PHPUnit testing to add your own assert. I think this is messy, but you could include your own set of routines in the bootstrap.php file. For this same test though, we simply assertEquals, assertTrue, etc... and use the basic PHP functions. PHPUnit is a testing framework, not a complete replacement for PHP functionality. – Steven Scott Jun 03 '14 at 15:58
  • Another reason this function would be great to have is for doing comparisons of result and expected values in IDEs such as PhpStorm. Comparing "True" and "False" is really not that helpful, whereas being able to examine the haystack itself would be extremely helpful. – Nathan Arthur Jun 11 '14 at 15:40
  • @Steven Scott If that is really your opinion then why on earth do we have assertEquals and assertTrue?!! – TheStoryCoder Jun 16 '14 at 11:03
  • @TheStoryCoder We use the assertEquals() with tolower() etc... to accomplish what you are trying. The asserts are used to ensure our testing in PHPUnit throws the errors to fail builds, etc... I am not sure which opinion you are wondering about though? PHP is still very useful in the tests, with the PHPUnit framework combining the test structure and reporting. – Steven Scott Jun 16 '14 at 15:43
  • I always find myself coming back to this answer about how to do the equivalent of stringContains in `with()` using Mockery https://stackoverflow.com/a/46922330/470749 – Ryan Dec 03 '19 at 00:44

6 Answers6

84

As you could tell assertContains is for checking that an array contains a value.

Looking to see if the string contains a substring, your simplest query would be to use assertRegexp()

$this->assertRegexp('/flour/', $plaintext);

You would just need to add the delimiters.

If you really want to have an assertStringContains assertion, you can extend PHPUnit_Framework_TestCase and create your own.

UPDATE

In the pre-9 versions of PHPUnit, assertContains will work on strings.

From 9+ we need to use assertStringContainsString or assertStringContainsStringIgnoringCase.

TheStoryCoder
  • 3,403
  • 6
  • 34
  • 64
Schleis
  • 41,516
  • 7
  • 68
  • 87
  • 16
    More recent versions of phpunit can do assertContains string. – Jeremy French Sep 26 '14 at 14:21
  • 6
    Update in v9 : assertStringContainsString or assertStringContainsStringIgnoringCase – François Breton May 22 '19 at 16:03
  • 3
    We can use these methods of PHPUnit: assertStringContainsString() or assertStringContainsStringIgnoringCase() AND assertStringNotContainsString() or assertStringNotContainsStringIgnoringCase() By the way note that assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. – FFinn Nov 29 '19 at 10:39
  • 1
    @schleis UPDATE assertContains doesn't work anymore on string (9.5.20) Had to use `assertTrue(str_contains(...̀ – St3an Apr 29 '22 at 06:56
78

You can always hide the ugliness inside a custom assertion method, so basically I would have a BaseTestCase class which inherits from the phpunit test case which you could use to have your own library of reusable assertions (see http://xunitpatterns.com/Custom%20Assertion.html).. (In php 5.4 you can use traits as well, imho assertion libraries are one of the cases where traits actually are useful)..I always introduce quite a few custom assertions in my projects, often domain specific. And yes, some are ugly too:) well, I guess that's what encapsulation is there for... Amongst things...:)

UPDATE: I just checked and 'assertContains' and 'assertNotContains' actually also operate on strings as well as arrays (and anything that implements 'Traversable'):

function test_Contains()
{
    $this->assertContains("test", "this is a test string" );
    $this->assertNotContains("tst", "this is a test string");
}
malte
  • 1,439
  • 1
  • 11
  • 12
  • 1
    PHPUnit\Framework\Exception: Argument #2 (No Value) of PHPUnit\Framework\Assert::assertContains() must be a array, traversable or string – Farid Movsumov Nov 04 '17 at 21:23
  • 2
    this behaviour is deprecated – scones Feb 25 '19 at 14:05
  • 5
    Was fine in 2015 but under PHP 8.1 throws a fatal error: `TypeError: PHPUnit\Framework\Assert::assertContains(): Argument #2 ($haystack) must be of type iterable, string given`. We can migrate to assertStringContainsString. – Dereckson Mar 12 '22 at 14:09
78

2019+ and PHPUnit 8.0+ update

assertContains() is deprecated since PHPUnit 8.0, see issue #3425.


Now the specific method is recommended (see issue #3422):

$plaintext = 'I fell on the flour';
$this->assertStringContainsString('flour', $plaintext);

TIP: Upgrade instantly with Rector and PHPUnit 8.0 set.

Tomas Votruba
  • 23,240
  • 9
  • 79
  • 115
  • 1
    Clear answer, to the point and updated to latest version. This is the valid reply for me. I see other answers with higher score, but if the framework has an specific method for this I don't see why use workarounds like "assertRegexp". – Miquel Canal Jan 27 '21 at 10:51
  • 1
    Workarounds were for older versions. This is the correct answer for PHPUnit 8+. – Mat Lipe Dec 08 '21 at 16:08
-1

You can do asserts against anything, including vanilla PHP functions. If you assert that strpos for the substring you're interested in on the string you're testing doesn't return FALSE it will meet your needs.

Make sure you're checking against FALSE though, and not something that evaluates to FALSE such as 0 (which is what strpos will return if the string being tested starts with the given substring).

GordonM
  • 31,179
  • 15
  • 87
  • 129
  • I just wanted something cleaner than using strpos() for that very reason you are mentioning! But I guess it just doesn't exist. – TheStoryCoder Jun 03 '14 at 13:50
-1

Extending from @Schleis, if you have more complicated strings you will need to escape the regex:

$this->assertRegexp('/' . preg_quote('[some $stuff]') . '/', $plaintext);

Or wrap it up in a neater method:

public function assertStringContains($needle, $haystack)
{
    $this->assertRegexp('/' . preg_quote($needle) . '/', $haystack);
}
Elliot Chance
  • 5,526
  • 10
  • 49
  • 80
-2

Can't you just do the string in string using the plain PHP functions available, and then assertEquals the output of that? Granted, it's not as shiny, but it works.

Alternatively you can use assertThat with a regular expression.

It sounds like something is inherently wrong with the design of the code / test though, from the limited perspective of the example. Why would a function return a complex string of unknown length, with the expected bit 'somewhere' in the string?

In the test you should be able to control your input, so you should know your entire expected output string. If your function ruins other parts of the string just this assertion wouldn't tell you about it. Which is probably why the assertStringContains function doesn't exist.

  • Yeah, I was looking for the shiny way to do it. I'm testing retrieving a webpage to which I have posted variables so I want to test if the request was OK based on whether or not a string exists in that page. Can't see how I can do that any differently. – TheStoryCoder Jun 03 '14 at 13:56